jabs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.gitmodules +3 -0
- data/README +20 -0
- data/Rakefile.rb +66 -0
- data/VERSION +1 -0
- data/build +29 -0
- data/examples/editor.html +22 -0
- data/examples/editor.js +58 -0
- data/examples/input_with_default.html +13 -0
- data/examples/input_with_default.js +19 -0
- data/examples/src/editor.html.haml +19 -0
- data/examples/src/editor.js.jabs +50 -0
- data/examples/src/input_with_default.html.haml +10 -0
- data/examples/src/input_with_default.js.jabs +10 -0
- data/lib/jabs.rb +308 -0
- data/lightning.jabs +33 -0
- data/rspec/fixtures/example.js +36 -0
- data/rspec/fixtures/example.js.jabs +24 -0
- data/rspec/fixtures/mephisto.js +56 -0
- data/rspec/fixtures/mephisto.js.jabl +25 -0
- data/rspec/jabs/jabs_engine_spec.rb +472 -0
- data/rspec/jabs/jabs_precompiler_spec.rb +37 -0
- data/rspec/jabs_spec.rb +15 -0
- data/rspec/jabs_spec_helper.rb +5 -0
- data/vendor/jquery/jquery-1.2.6.pack.js.gz +11 -0
- data/vendor/jquery/jquery-1.3.1.js +4241 -0
- data/vendor/jquery/jquery.simulate.js +152 -0
- metadata +110 -0
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/README
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Javascript Abstract Behavior Syntax? What's that?
|
2
|
+
|
3
|
+
I was working on a project *very* similar to http://github.com/nex3/jabl in the months running up to RubyFringe.
|
4
|
+
|
5
|
+
Then I saw Hampton's presenation. Oops.
|
6
|
+
|
7
|
+
Well I had all this work and I wanted to see what it'd take to get it producing usable javascript.
|
8
|
+
|
9
|
+
I pulled it out of http://github.com/collin/lucky7 and stuck it here.
|
10
|
+
|
11
|
+
And hacked around a bit, removing some features, adding others.
|
12
|
+
|
13
|
+
Check it out:
|
14
|
+
|
15
|
+
(add github to rubygems)
|
16
|
+
gem install collin-fold
|
17
|
+
git://github.com/collin/jabs.git
|
18
|
+
cd jabs
|
19
|
+
|
20
|
+
Look through /examples
|
data/Rakefile.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'pathname'
|
3
|
+
require 'launchy'
|
4
|
+
|
5
|
+
__DIR__ = Pathname.new(__FILE__).dirname
|
6
|
+
$LOAD_PATH << __DIR__ unless $LOAD_PATH.include?(__DIR__)
|
7
|
+
|
8
|
+
task :default => "spec:all"
|
9
|
+
|
10
|
+
namespace :spec do
|
11
|
+
task :default => :all
|
12
|
+
|
13
|
+
task :prepare do
|
14
|
+
@specs= Pathname.glob(__DIR__ + "rspec" + "**" + "*.rb").join(' ')
|
15
|
+
p @specs
|
16
|
+
end
|
17
|
+
|
18
|
+
task :all => :prepare do
|
19
|
+
system "spec #{@specs}"
|
20
|
+
end
|
21
|
+
|
22
|
+
task :doc => :prepare do
|
23
|
+
system "spec #{@specs} --format specdoc"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
task :example do#=> "spec:all" do
|
28
|
+
require 'lib/jabs'
|
29
|
+
examples = __DIR__ + "examples"
|
30
|
+
jabs = (examples + "input_with_default.js.jabs").read
|
31
|
+
jabs_en = Jabs::Engine.new(jabs)
|
32
|
+
js = jabs_en.render
|
33
|
+
target = examples + "input_with_default.js"
|
34
|
+
js_file = File.new(target, 'w')
|
35
|
+
js_file.write(js)
|
36
|
+
js_file.close
|
37
|
+
|
38
|
+
haml = (examples + "layout.html.haml").read
|
39
|
+
haml_en = Haml::Engine.new(haml)
|
40
|
+
html = haml_en.render :example => target
|
41
|
+
html_file = File.new("layout.html", 'w')
|
42
|
+
html_file.write(html)
|
43
|
+
html_file.close
|
44
|
+
|
45
|
+
browser = Launchy::Browser.new
|
46
|
+
browser.visit(target)
|
47
|
+
end
|
48
|
+
|
49
|
+
begin
|
50
|
+
require 'jeweler'
|
51
|
+
Jeweler::Tasks.new do |gemspec|
|
52
|
+
gemspec.name = "jabs"
|
53
|
+
gemspec.summary = "Javascript Abstract Behavior Syntax"
|
54
|
+
gemspec.description = "Inspiredby HAML, SASS and JABL by mr Hampton Catlin"
|
55
|
+
gemspec.email = "collintmiller@gmail.com"
|
56
|
+
gemspec.homepage = "http://github.com/collin/jabs"
|
57
|
+
gemspec.authors = ["Collin Miller"]
|
58
|
+
|
59
|
+
gemspec.add_dependency('fold', '0.5.0')
|
60
|
+
gemspec.add_dependency('johnson', '1.1.2')
|
61
|
+
gemspec.add_dependency('colored', '1.1')
|
62
|
+
end
|
63
|
+
Jeweler::GemcutterTasks.new
|
64
|
+
rescue LoadError
|
65
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
66
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/build
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << "/home/collin/code/lucky7/lib"
|
4
|
+
Lucky7Root = ""
|
5
|
+
require 'rubygems'
|
6
|
+
require 'lucky7'
|
7
|
+
require 'lib/jabs'
|
8
|
+
require 'haml'
|
9
|
+
|
10
|
+
__DIR__ = Pathname.new(__FILE__).dirname.expand_path
|
11
|
+
|
12
|
+
class JabsExampleBuilder < Lucky7::Builder
|
13
|
+
SrcRegex = /src/
|
14
|
+
BuildDirectory = ""
|
15
|
+
|
16
|
+
builds Haml, :files => "/home/collin/code/jabs/examples/src/*.html.haml"
|
17
|
+
builds Jabs, :files => "/home/collin/code/jabs/examples/src/*.js.jabs"
|
18
|
+
|
19
|
+
def build files=modified_files
|
20
|
+
super
|
21
|
+
require 'pp'
|
22
|
+
pp modified_files
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
# JabsExampleBuilder.new.build_all
|
28
|
+
JabsExampleBuilder.new.build_continuously
|
29
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Generated By Jabs</title>
|
5
|
+
<meta content='text/html; charset=utf-8' http-equiv='content-type' />
|
6
|
+
<script src='../vendor/jquery/jquery-1.2.6.js'></script>
|
7
|
+
<script src='editor.js'></script>
|
8
|
+
<style>
|
9
|
+
span {
|
10
|
+
float: left;
|
11
|
+
white-space: pre; }
|
12
|
+
|
13
|
+
#cursor {
|
14
|
+
width: 1px;
|
15
|
+
height: 16px;
|
16
|
+
background: black; }
|
17
|
+
</style>
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<span id='cursor'></span>
|
21
|
+
</body>
|
22
|
+
</html>
|
data/examples/editor.js
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
var Backspace = 8;
|
2
|
+
var Tab = 9;
|
3
|
+
var Enter = 13;
|
4
|
+
var Shift = 16;
|
5
|
+
var Ctrl = 17;
|
6
|
+
var Alt = 18;
|
7
|
+
var PauseBreak = 19;
|
8
|
+
var CapsLock = 20;
|
9
|
+
var Escape = 27;
|
10
|
+
var PageUp = 33;
|
11
|
+
var PageDown = 34;
|
12
|
+
var PageEnd = 35;
|
13
|
+
var PageHome = 36;
|
14
|
+
var Left = 37;
|
15
|
+
var Up = 38;
|
16
|
+
var Right = 39;
|
17
|
+
var Down = 40;
|
18
|
+
var Insert = 45;
|
19
|
+
var Delete = 46;
|
20
|
+
jQuery.fn.blink = function() {
|
21
|
+
this.toggle();
|
22
|
+
var that = this;
|
23
|
+
t = window.setTimeout(function() {
|
24
|
+
that.blink();
|
25
|
+
}, 1000);
|
26
|
+
return this;
|
27
|
+
};
|
28
|
+
jQuery(function() {
|
29
|
+
(function($this) {
|
30
|
+
$this.bind("keypress", function(e) {
|
31
|
+
e.preventDefault();
|
32
|
+
(function($this) {
|
33
|
+
$this.show();
|
34
|
+
function insert(val) {
|
35
|
+
$this.before(val);
|
36
|
+
}
|
37
|
+
if(e.charCode) {
|
38
|
+
insert("<span>" + String.fromCharCode(e.charCode) + "</span>");
|
39
|
+
}
|
40
|
+
if(e.keyCode === Backspace) {
|
41
|
+
$this.prev().remove();
|
42
|
+
}
|
43
|
+
if(e.keyCode === Left) {
|
44
|
+
$this.prev().before($this);
|
45
|
+
}
|
46
|
+
if(e.keyCode === Right) {
|
47
|
+
$this.next().after($this);
|
48
|
+
}
|
49
|
+
if(e.keyCode === Enter) {
|
50
|
+
insert("<br/>");
|
51
|
+
}
|
52
|
+
})(jQuery("#cursor"));
|
53
|
+
});
|
54
|
+
(function($this) {
|
55
|
+
$this.blink();
|
56
|
+
})(jQuery("#cursor"));
|
57
|
+
})(jQuery(window));
|
58
|
+
});
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Generated By Jabs</title>
|
5
|
+
<meta content='text/html; charset=utf-8' http-equiv='content-type' />
|
6
|
+
<script src='../vendor/jquery/jquery-1.2.6.js'></script>
|
7
|
+
<script src='input_with_default.js'></script>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<input default_value='hello!' type='text' />
|
11
|
+
<input default_value='hello again!' type='text' />
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
jQuery(function() {
|
2
|
+
(function($this) {
|
3
|
+
(function($this) {
|
4
|
+
$this.bind("blur", function(e) {
|
5
|
+
var $this = jQuery(this);
|
6
|
+
if($this.attr("value") === "") {
|
7
|
+
$this.attr("value", $this.attr("default_value"));
|
8
|
+
}
|
9
|
+
});
|
10
|
+
$this.bind("focus", function(e) {
|
11
|
+
var $this = jQuery(this);
|
12
|
+
if($this.attr("value") === $this.attr("default_value")) {
|
13
|
+
$this.attr("value", "");
|
14
|
+
}
|
15
|
+
});
|
16
|
+
$this.blur();
|
17
|
+
})(jQuery("input[default_value]"));
|
18
|
+
})(jQuery(window));
|
19
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title Generated By Jabs
|
5
|
+
%meta{"http-equiv"=>"content-type", "content"=>"text/html; charset=utf-8"}
|
6
|
+
%script{:src=> "../vendor/jquery/jquery-1.2.6.js"}
|
7
|
+
%script{:src=> "editor.js"}
|
8
|
+
%style
|
9
|
+
:sass
|
10
|
+
span
|
11
|
+
:float left
|
12
|
+
:white-space pre
|
13
|
+
|
14
|
+
#cursor
|
15
|
+
:width 1px
|
16
|
+
:height 16px
|
17
|
+
:background black
|
18
|
+
%body
|
19
|
+
%span#cursor
|
@@ -0,0 +1,50 @@
|
|
1
|
+
var Backspace = 8;
|
2
|
+
var Tab = 9;
|
3
|
+
var Enter = 13;
|
4
|
+
var Shift = 16;
|
5
|
+
var Ctrl = 17;
|
6
|
+
var Alt = 18;
|
7
|
+
var PauseBreak = 19;
|
8
|
+
var CapsLock = 20;
|
9
|
+
var Escape = 27;
|
10
|
+
var PageUp = 33;
|
11
|
+
var PageDown = 34;
|
12
|
+
var PageEnd = 35;
|
13
|
+
var PageHome = 36;
|
14
|
+
var Left = 37;
|
15
|
+
var Up = 38;
|
16
|
+
var Right = 39;
|
17
|
+
var Down = 40;
|
18
|
+
var Insert = 45;
|
19
|
+
var Delete = 46;
|
20
|
+
|
21
|
+
jQuery.fn.blink = function() { this.toggle(); var that = this; t = window.setTimeout(function() {that.blink();}, 1000); return this};
|
22
|
+
|
23
|
+
:ready
|
24
|
+
:keypress
|
25
|
+
e.preventDefault()
|
26
|
+
$#cursor
|
27
|
+
.show()
|
28
|
+
|
29
|
+
fun insert val
|
30
|
+
.before(val)
|
31
|
+
|
32
|
+
if e.charCode
|
33
|
+
insert("<span>"+String.fromCharCode(e.charCode)+"</span>")
|
34
|
+
|
35
|
+
if e.keyCode === Backspace
|
36
|
+
.prev().remove()
|
37
|
+
|
38
|
+
if e.keyCode === Left
|
39
|
+
.prev().before($this)
|
40
|
+
|
41
|
+
if e.keyCode === Right
|
42
|
+
.next().after($this)
|
43
|
+
|
44
|
+
if e.keyCode === Enter
|
45
|
+
insert("<br/>")
|
46
|
+
|
47
|
+
|
48
|
+
$#cursor
|
49
|
+
.blink()
|
50
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title Generated By Jabs
|
5
|
+
%meta{"http-equiv"=>"content-type", "content"=>"text/html; charset=utf-8"}
|
6
|
+
%script{:src=> "../vendor/jquery/jquery-1.2.6.js"}
|
7
|
+
%script{:src=> "input_with_default.js"}
|
8
|
+
%body
|
9
|
+
%input{:type=>'text', :default_value => "hello!"}/
|
10
|
+
%input{:type=>'text', :default_value => "hello again!"}/
|
data/lib/jabs.rb
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fold'
|
5
|
+
require 'johnson'
|
6
|
+
|
7
|
+
module Johnson
|
8
|
+
module Nodes
|
9
|
+
attr_accessor :value
|
10
|
+
class FallThrough < Node
|
11
|
+
def initialize(_row, _column, value)
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Visitors
|
18
|
+
class EcmaVisitor
|
19
|
+
def visit_SourceElements(o)
|
20
|
+
newline = o.value.length > 0 ? "\n" : ' '
|
21
|
+
(@depth == 0 ? '' : "{#{newline}") +
|
22
|
+
indent {
|
23
|
+
o.value.map { |x|
|
24
|
+
code = x.accept(self)
|
25
|
+
semi = case x
|
26
|
+
when Nodes::FallThrough
|
27
|
+
""
|
28
|
+
when Nodes::Function, Nodes::While, Nodes::If, Nodes::Try, Nodes::Switch, Nodes::Case, Nodes::Default, Nodes::For, Nodes::ForIn
|
29
|
+
code =~ /\}\Z/ ? '' : ';'
|
30
|
+
else
|
31
|
+
';'
|
32
|
+
end
|
33
|
+
"#{indent}#{code}#{semi}"
|
34
|
+
}.join("\n")
|
35
|
+
} +
|
36
|
+
(@depth == 0 ? '' : "#{newline}}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def visit_FallThrough(o)
|
40
|
+
o.value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class SexpVisitor
|
45
|
+
def visit_FallThrough(o)
|
46
|
+
[:fall_through, o.value]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module Jabs
|
53
|
+
include Johnson::Nodes
|
54
|
+
|
55
|
+
def self.logger
|
56
|
+
@logger ||= begin
|
57
|
+
#TODO configurable logging
|
58
|
+
logger = Logger.new STDOUT
|
59
|
+
logger.level = Logger::DEBUG
|
60
|
+
logger.progname = "jabs"
|
61
|
+
logger.info "Started Logging"
|
62
|
+
logger
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Precompiler < Fold::Precompiler
|
67
|
+
class << self
|
68
|
+
attr_accessor :spot_replacements
|
69
|
+
end
|
70
|
+
|
71
|
+
self.spot_replacements = []
|
72
|
+
|
73
|
+
def self.spot_replace key, &block
|
74
|
+
spot_replacements << block if block_given?
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_reader :sexp, :current_sexp
|
78
|
+
|
79
|
+
def initialize
|
80
|
+
super
|
81
|
+
|
82
|
+
@ready = false
|
83
|
+
@current_sexp = []
|
84
|
+
@full_sexp = [:source_elements, @current_sexp]
|
85
|
+
end
|
86
|
+
|
87
|
+
folds :Line, // do
|
88
|
+
[:fall_through, (Precompiler.do_spot_replace(text, self) + children.map{|child| child.text}.join(""))]
|
89
|
+
end
|
90
|
+
|
91
|
+
folds :Selector, /^\$/ do
|
92
|
+
call(function(nil, ["$this"], [:source_elements, render_children]), jquery([:string, text]))
|
93
|
+
end
|
94
|
+
|
95
|
+
folds :SubSelector, /^&/ do
|
96
|
+
call(
|
97
|
+
function(nil, ["$this"], [:source_elements, render_children]),
|
98
|
+
call(access([:name, "$this"], [:name, "find"]), [:string, text])
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
folds :Event, /^:/ do
|
103
|
+
event_bind(text, [:name, "$this"], [:source_elements, [parse("var $this = jQuery(this)")] + render_children])
|
104
|
+
end
|
105
|
+
|
106
|
+
folds :Ready, /^:ready/ do
|
107
|
+
jquery(function(nil, [], [:source_elements, [call(function(nil, ["$this"], [:source_elements, render_children]), jquery([:name, "window"]))]]))
|
108
|
+
end
|
109
|
+
|
110
|
+
folds :Function, /^fun / do
|
111
|
+
parts = text.split(/ /)
|
112
|
+
name, arg_names = parts.shift, parts.join('').gsub(' ', '').split(',')
|
113
|
+
[:function, name, arg_names, [:source_elements, render_children]]
|
114
|
+
end
|
115
|
+
|
116
|
+
folds :Def, /^def / do
|
117
|
+
parts = text.split(/ /)
|
118
|
+
name, arg_names = parts.shift, parts.join('').gsub(' ', '').split(',')
|
119
|
+
[:assign_expr,
|
120
|
+
access(access([:name, "jQuery"], [:name, "fn"]), [:name, name]),
|
121
|
+
[:function, nil, arg_names, [:source_elements, [parse("var $this = this")] + render_children]]]
|
122
|
+
end
|
123
|
+
|
124
|
+
if_meta = %q{
|
125
|
+
index = parent.children.index(self)
|
126
|
+
_next = parent.children.slice index + 1
|
127
|
+
|
128
|
+
_else = if [Else, ElseIf].include? _next.class
|
129
|
+
_next.render
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
[:if, parse(Precompiler.do_spot_replace(text)),[:source_elements, render_children], _else]
|
134
|
+
}
|
135
|
+
|
136
|
+
folds :If, /^if / do
|
137
|
+
eval if_meta
|
138
|
+
end
|
139
|
+
|
140
|
+
folds :Unless, /^unless / do
|
141
|
+
[:if, [:not, [:parenthesis, parse(Precompiler.do_spot_replace(text))]], [:source_elements, render_children], nil]
|
142
|
+
end
|
143
|
+
|
144
|
+
folds :Else, /^else/ do
|
145
|
+
[:source_elements, render_children]
|
146
|
+
end
|
147
|
+
|
148
|
+
folds :ElseIf, /^else if/ do
|
149
|
+
eval if_meta
|
150
|
+
end
|
151
|
+
|
152
|
+
folds :DotAccessor, /^\./ do
|
153
|
+
index = parent.children.index(self)
|
154
|
+
_next = parent.children.slice index + 1
|
155
|
+
_text = _next ? _next.text : ""
|
156
|
+
if children.any?
|
157
|
+
if (_text[/\}\)/])
|
158
|
+
[:fall_through, ("$this."+Precompiler.do_spot_replace(text, self) + children.map{|child| child.text}.join(""))]
|
159
|
+
else
|
160
|
+
call(
|
161
|
+
function(nil, ["$this"], [:source_elements, render_children]),
|
162
|
+
parse(Precompiler.do_spot_replace(".#{text}", self))
|
163
|
+
)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
parse Precompiler.do_spot_replace(".#{text}", self)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
spot_replace :DotAccessor do |expression, precompiler|
|
171
|
+
expression.gsub /(^\.([\w]+)|- \.(.+))(.*)/ do |match|
|
172
|
+
"$this#{Precompiler.compile_arguments expression, $1, match, $4}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
spot_replace :AccessUpAndCall do |expression, precompiler|
|
177
|
+
expression.gsub /\.\.(\..*)/ do |match|
|
178
|
+
"$this.prevObject#{Precompiler.do_spot_replace($1)}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
spot_replace :AccessUpUp do |expression, precompiler|
|
183
|
+
expression.
|
184
|
+
gsub(/ \.\.\/|^\.\.\//, "$this.prevObject/").
|
185
|
+
gsub(/\/\.\./, ".prevObject")
|
186
|
+
end
|
187
|
+
|
188
|
+
spot_replace :AccessUp do |expression, precompiler|
|
189
|
+
expression.gsub /\.\./ do
|
190
|
+
"$this.prevObject"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
spot_replace :AttributeSetter do |expression, precompiler|
|
195
|
+
expression.gsub /@([\w]+)[ ]*=[ ]*(.*)/ do |match|
|
196
|
+
if $2[0] == ?=
|
197
|
+
match
|
198
|
+
else
|
199
|
+
"$this.attr('#{$1}', #{Precompiler.do_spot_replace $2, precompiler})"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
spot_replace :AttributeAccessor do |expression, precompiler|
|
205
|
+
expression.gsub /@([\w]+)/ do
|
206
|
+
"$this.attr('#{$1}')"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
spot_replace :DanglingThis do |expression, precompiler|
|
211
|
+
expression.gsub /prevObject\$this/ do
|
212
|
+
"prevObject"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.do_spot_replace expression, precompiler=nil
|
217
|
+
spot_replacements.each do |block|
|
218
|
+
expression = block.call(expression, precompiler)
|
219
|
+
end
|
220
|
+
expression
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.compile_arguments expression, call, real, args
|
224
|
+
return real if expression[Regexp.new("^\\#{call}\\(")]
|
225
|
+
arguments = []
|
226
|
+
if args[/^\./]
|
227
|
+
"#{call}()#{do_spot_replace(args).gsub("$this", "")}"
|
228
|
+
else
|
229
|
+
args.split(/\s|,/).each do |arg|
|
230
|
+
arg.gsub!(/:(\w+)/) {%{"#{$1}"}}
|
231
|
+
next if arg[/\s/]
|
232
|
+
next if arg == ""
|
233
|
+
arguments << arg
|
234
|
+
end
|
235
|
+
"#{call}(#{arguments.join(', ')})"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def parse expression
|
240
|
+
self.class.do_spot_replace expression, self
|
241
|
+
Johnson::Parser.parse(expression).value.first
|
242
|
+
end
|
243
|
+
|
244
|
+
def source block=nil
|
245
|
+
source = [:source_elements]
|
246
|
+
source << [block] unless(block.nil? or block.empty?)
|
247
|
+
source
|
248
|
+
end
|
249
|
+
|
250
|
+
def event_bind event, binds_to, function_sexp=nil
|
251
|
+
call(access(binds_to, [:name, "live"]), [:string, event], function(nil, ["e"], function_sexp))
|
252
|
+
end
|
253
|
+
|
254
|
+
def call *args
|
255
|
+
[:function_call, args]
|
256
|
+
end
|
257
|
+
|
258
|
+
def onready function_sexp=nil
|
259
|
+
event_bind('ready', jquery([:name, "document"]), function_sexp)
|
260
|
+
end
|
261
|
+
|
262
|
+
def access left, right
|
263
|
+
[:dot_accessor, right, left]
|
264
|
+
end
|
265
|
+
|
266
|
+
def function name=nil, args=[], function_sexp=nil
|
267
|
+
[:function, name, args, function_sexp]
|
268
|
+
end
|
269
|
+
|
270
|
+
def jquery *jquery_arg
|
271
|
+
[:function_call, [
|
272
|
+
[:name, 'jQuery'],
|
273
|
+
*jquery_arg
|
274
|
+
]]
|
275
|
+
end
|
276
|
+
|
277
|
+
def johnsonize(sexp)
|
278
|
+
return sexp if sexp.is_a?(Johnson::Nodes::Node)
|
279
|
+
return sexp if sexp.class.to_s == "String"
|
280
|
+
return [] if sexp === []
|
281
|
+
return nil if sexp === nil
|
282
|
+
unless sexp.first.class.to_s == "Array"
|
283
|
+
if sexp.first.class.to_s == "Symbol"
|
284
|
+
klass = eval("Johnson::Nodes::#{sexp.shift.to_s.camelcase}")
|
285
|
+
klass.new 0,0, *sexp.map{|n|johnsonize(n)}
|
286
|
+
elsif sexp.is_a? Array
|
287
|
+
sexp.map{|n|johnsonize(n)}
|
288
|
+
else
|
289
|
+
sexp
|
290
|
+
end
|
291
|
+
else
|
292
|
+
sexp.map{|n|johnsonize(n)}
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
class Engine < Fold::Engine
|
298
|
+
|
299
|
+
def render context=nil
|
300
|
+
@p = precompiler_class.new
|
301
|
+
root = Johnson::Nodes::SourceElements.new 0, 0
|
302
|
+
@p.fold(lines).children.each{|c|root << @p.johnsonize(c.render)}
|
303
|
+
root.to_ecma
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
puts Jabs::Engine.new($stdin.read).render if $0 == __FILE__
|