jabs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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__
|