README.md in jsrb-0.2.1 vs README.md in jsrb-0.3.0

- old
+ new

@@ -4,261 +4,274 @@ Jsrb is a template engine to generate JavaScript code in simple Ruby DSL. # Getting Started -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`. +Jsrb handler works in `.jsrb` view files. All ruby syntax is available and `js` is provided in it. You can construct JavaScript code via `js`. -```rb -name = jsrb.var!(:name) { 'foo' } -ary = jsrb.var! :ary -obj = jsrb.var! :obj -result = jsrb.var! +```ruby +name = js.var!(:name) { 'foo' } +ary = js.var! :ary +obj = js.var! :obj +result = js.var! # var name = 'foo'; # var ary; # var obj; -# var _v1; <- auto generate variable name +# var _v1; // auto generated -ary.set!([1, 2, 3]) +js.set! ary, [1, 2, 3] # ary = [1, 2, 3]; -obj.set!( +js.set! obj, { name: name, profile: { age: 20, sex: 'm' } -) +} # obj = { # name: name, # profile: { # age: 20, # sex: 'm' # } # }; -result.set! (obj.name + "(" + obj.profile.age + ")") +js.set! result, (obj.name + "(" + obj.profile.age + ")") # _v1 = obj.name + "(" + obj.profile.age + ")"; -ary.set! ary.map { |x| x * 2 } +js.set! ary, ary.map { |x| x * 2 } # ary = ary.map(function(x) { # return x * 2; # }); -jsrb.if!(ary[1] === 4) { - result.set! 'four' +js.if!(ary[1] === 4) { + js.set! result, 'four' }.elsif(ary[1] === 2) { - result.set! 'two' + js.set! result, 'two' }.else { - result.set! 'other' + js.set! result, 'other' } -# // the actual output doesn't looks like this, but will be better code in regard to variable scope. +# // The actual output will have certain immediate functions +# // that preserve variable scope for each case. # if (ary[1] === 4) { # _v1 = 'four' # } else if (ary[1] === 2) { # _v1 = 'two' # } else { # _v1 = 'other' # } -result.set! jsrb.expr.Date.new! +js.set! result, js.expr.Date.new # _v1 = new Date; -jsrb.expr.console.log('hello').as_statement! +js.set! js.expr.console.log('hello') # console.log('hello'); ``` # Usage +In contrast to Ruby, statements and expressions are +specifically distinguished as different elements in JavaScript. +And the program is composed of a list of statements. +This means that the jsrb file will have a series of statement pushing expression in it. + +To make clear whether a method is pushing statement or not, jsrb adopted the rule that the name of method pushing statement should be `#..!`. + ## Statements ### Variable declaration -`jsrb.var!` pushes a **VariableDeclaration** into current context. +`js.var!` pushes a **VariableDeclaration** into current context. -```rb +```ruby # with variable name and initializer -jsrb.var!('varname') { 100 } +js.var!('varname') { 100 } # var varname = 100; # without initializer -jsrb.var!('varname') +js.var!('varname') # var varname; # variable name is auto-generated if not specified -jsrb.var! +js.var! # var _v1; # var! returns Jsrb::ExprChain instance, so that you can # assign value with `.set!` method. -a = jsrb.var! -a.set! 100 +a = js.var! +js.set! a, 100 # var _v1; # v1 = 100; ``` ### If statement, and conditional expression -`jsrb.if!` pushes an **IfStatement** into current context, `jsrb.if` to build **a conditional expression**. +`js.if!` pushes an **IfStatement** into current context, `js.if` to build **a conditional expression**. -```rb +```ruby # start with `#if!` # and chain `#elsif` to add next case. # Note that this is a statement, not expression. -jsrb.if!(v === 1) { +js.if!(v === 1) { # .. }.elsif(v === 2) { # .. }.else { # .. } # if you don't need else clause, close with `#end` -jsrb.if!(v === 1) { +js.if!(v === 1) { # .. }.end # if you want to regard this as an expression, use `#if` without exclamation. -v.set! jsrb.if(v === 1) { +js.set! v, js.if(v === 1) { # .. }.else { # .. } ``` -### Assignment statement - -`ExprChain#set!` pushes an **assignment statement** (ExpressionStatement of AssignmentExpression). - -```rb -a = jsrb.var! :a -a.set! 100 -# var a; -# a = 100; -``` - ### Expression statement -`ExprChain#as_statement!` pushes an **ExpressionStatement** of the left hand side of chain. +`js.do!` pushes an **ExpressionStatement** of a given expression. -```rb -get_elements = jsrb.expr['getElements'] -get_elements.('.foo').forEach { |n| n.delete.() }.as_statement! +```ruby +get_elements = js.expr[:getElements] +js.do! get_elements.('.foo').forEach { |n| n.delete.() } # getElements('.foo').forEach(function(n) { return n.delete(); }); ``` -## Expression chain +## Expressions Expression chain (`ExprChain` class) is an utility class to construct JavaScript expressions. -### Initialize with wrapping a ruby value +### Initialize with wrapping ruby values -`jsrb.expr` create a new `ExprChain` instance, taking an initial value optionally. -Some methods in jsrb automatically convert ruby expression to ExprChain. +`js.expr` create a new `ExprChain` instance, taking an initial value optionally. +Some methods in `js` automatically convert ruby value to ExprChain. -```rb -x = jsrb.var! :x +```ruby +x = js.var! :x -x.set! jsrb.expr(100) +js.set! x, js.expr(100) # x = 100; -# set! automatically wrap with ExprChain. -x.set! 100 +# set! automatically wraps argument with ExprChain. +js.set! x, 100 # x = 100; -# If you need to compare by operator with another ExprChain, -# you have to wrap first. -x.set!(jsrb.expr(100) < jsrb.expr.y) -# x.set!(100 < jsrb.expr.y) will fail. +# +# Note that if you need to compare a ruby value by operator with another one, +# you have to wrap it. +js.set! x, (js.expr(100) < js.expr.y) # (100 < js.expr.y) will fail. ``` +See the conversion section to check mappings from ruby value to JavaScript one. + ### Chains #### Member expression -`ExprChain#[], #member!, #..` constructs **MemberExpression**. +`ExprChain#[], #..` constructs **MemberExpression**. `#[]` and `#member!` is safe. `#..` can be used only if the name has no conflict. -```rb -x = jsrb.var! :x +```ruby +x = js.var! :x -obj = jsrb.expr['someObj'] -# jsrb.expr with no argument constructs empty chain, +obj = js.expr[:someObj] +# js.expr with no argument constructs empty chain, # in which every member chain will be an identifier. -x.set! obj.field +js.set! x, obj.field # x = someObj['field']; -x.set! obj['field'] +js.set! x, obj[:field] # x = someObj['field']; -x.set! obj.member! 'field' -# x = someObj['field']; -x.set! obj.send # NOTE that this is interpreted as a ruby Object's method, and causes an error. +js.set! x, obj.send # NOTE that this is interpreted as a ruby Object's method, and causes an error. ``` +#### Assignment + +`ExprChain#set` constructs an **AssignmentExpression**. + +```ruby +a = js.var! :a +# var a; + +js.do! a.set 100 +# a = 100; + +# js.set!(a, b) is short hand of js.do!(a.set(b)) +js.set! a, 100 +# a = 100; +``` + #### Function Call `ExprChain#call, so #.(), #.. with argument or block` constructs **CallExpression**. -```rb -x = jsrb.var! :x -console = jsrb.expr['console'] +```ruby +console = js.expr[:console] # using call method -console.log.('foo').as_statement! +js.do! console.log.('foo') # console.log('foo') -console.log.call('foo').as_statement! +js.do! console.log.call('foo') # console.log('foo') # using dynamic method # if #..() has at least one argument or block, it will be a call expression. -console.log('foo').as_statement! +js.do! console.log('foo') # console.log('foo') -x.map { |item| item.field }.as_statement! -# x.map(function(item) { return item.field; }); + +js.do! js.expr(:ary).forEach { |item| item.execute.() } +# ary.forEach(function(item) { return item.execute(); }); ``` #### Operators Any ruby-overridable and JS-existing operators are overridden for chaining. Supported operators are: `** + - * / % >> << & ^ | <= < > >= == === != ! && ||`. -```rb -x = jsrb.var! :x -a = jsrb.expr['a'] +```ruby +x = js.var! :x +a = js.expr[:a] -x.set!(a === 1) +js.set! x, (a === 1) # x = a === 1; -x.set!(a * a) +js.set! x, (a * a) # x = a * a; -x.set!(3 * a) # raises an error because Fixnum does not accept ExprChain as RHS. +js.set! x, (3 * a) # raises an error because the method :* of Fixnum does not accept ExprChain as RHS. ``` #### New -`ExprChain#new!` constructs **NewExpression**. +`ExprChain#new` constructs **NewExpression**. -```rb -x = jsrb.var! :x +```ruby +x = js.var! :x -x.set! jsrb.expr['Date'].new! +js.set! x, js.expr[:Date].new # x = new Date; ``` #### Function expression -`ExprChain#for_all!` constructs **FunctionExpression**. You can also construct it from Proc directly or passing a block. +`ExprChain#forall` constructs **FunctionExpression**. You can also construct it directly from Proc or passing a block. -```rb -ary = jsrb.var! :ary, [1, 2, 3] +```ruby +ary = js.var! :ary, [1, 2, 3] -ary.map((jsrb.expr['x'] * 2).for_all!('x')).as_statement! +js.do! ary.map((js.expr[:x] * 2).forall('x')) # ary.map(function(x) { return x * 2; }); -ary.map { |x| x * 2 }.as_statement! +js.do! ary.map { |x| x * 2 } # ary.map(function(x) { return x * 2; }); -ary.map(->(x) { x * 2 }).as_statement! +js.do! ary.map(->(x) { x * 2 }) # ary.map(function(x) { return x * 2; }); ``` # Conversion @@ -281,13 +294,13 @@ # Customize Chain You can add custom chain methods in `ExprChain` via `Jsrb::ExprChain.#add_custom_chain`. -```rb +```ruby Jsrb::ExprChain.add_custom_chain('log_here', '__tap_log__') -jsrb.expr['foo']['bar'].log_here.as_statement! +js.do! js.expr[:foo][:bar].log_here # __tap_log__(foo['bar']); ``` ## Contributing