jabs 0.1.1 → 0.2.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/VERSION +1 -1
- data/examples/config.ru +16 -6
- data/examples/jabs/drag_and_drop.js.jabs +23 -0
- data/examples/{src → jabs}/input_with_default.js.jabs +1 -1
- data/examples/views/drag_and_drop.haml +16 -0
- data/examples/views/input_with_default.haml +3 -0
- data/examples/views/layout.haml +8 -0
- data/lib/jabs.rb +10 -289
- data/lib/jabs/engine.rb +18 -0
- data/lib/jabs/middleware.rb +17 -3
- data/lib/jabs/precompiler.rb +252 -0
- data/lib/johnson/ext.rb +44 -0
- data/{vendor/jquery/jquery-1.3.1.js → lib/jquery/jquery-1.3.2.js} +316 -181
- data/lib/jquery/jquery.event.drag-1.5.js +137 -0
- data/lib/jquery/jquery.event.drop-1.2.js +157 -0
- data/lib/jquery/jquery.focus_and_blur.js +81 -0
- data/rspec/jabs/jabs_engine_spec.rb +78 -16
- metadata +13 -12
- data/examples/editor.html +0 -22
- data/examples/editor.js +0 -58
- data/examples/input_with_default.html +0 -13
- data/examples/input_with_default.js +0 -19
- data/examples/src/editor.html.haml +0 -19
- data/examples/src/editor.js.jabs +0 -50
- data/examples/src/input_with_default.html.haml +0 -10
- data/vendor/jquery/jquery-1.2.6.pack.js.gz +0 -11
- data/vendor/jquery/jquery.simulate.js +0 -152
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/examples/config.ru
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
require 'lib/jabs'
|
2
2
|
require 'pathname'
|
3
|
+
require 'sinatra'
|
4
|
+
require 'haml'
|
5
|
+
require 'sass'
|
3
6
|
|
4
|
-
|
5
|
-
|
7
|
+
class Example < Sinatra::Base
|
8
|
+
set :views, Jabs.root+'../examples/views'
|
9
|
+
|
10
|
+
%w{input_with_default drag_and_drop}.each do |part|
|
11
|
+
get "/#{part}" do
|
12
|
+
haml part.intern
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
use Jabs::Rack::Static, :urls => '/jabs', :root => Pathname.new(__FILE__).dirname.expand_path
|
18
|
+
Jabs::Rack.mount(self, '/jquery')
|
19
|
+
map("/examples") { run Example.new }
|
6
20
|
|
7
|
-
use Jabs::Rack::Static, :urls => '/src', :root => Pathname.new(__FILE__).dirname.expand_path
|
8
|
-
run lambda { |env|
|
9
|
-
[200, {'Content-Type'=>'text/html'}, "JABS"]
|
10
|
-
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
:ready
|
2
|
+
$#sortable
|
3
|
+
.sortable 'li'
|
4
|
+
|
5
|
+
def sortable parent_selector
|
6
|
+
:dragstart
|
7
|
+
event.target
|
8
|
+
.closest parent_selector
|
9
|
+
.clone
|
10
|
+
.css
|
11
|
+
position: 'absolute'
|
12
|
+
.appendTo document.body
|
13
|
+
|
14
|
+
:drag
|
15
|
+
event.dragProxy
|
16
|
+
.css
|
17
|
+
top: event.pageY
|
18
|
+
left: event.pageX
|
19
|
+
|
20
|
+
:dragend
|
21
|
+
event.dragProxy
|
22
|
+
.remove
|
23
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%script{:src=> "/jabs/drag_and_drop.js.jabs"}
|
2
|
+
%style
|
3
|
+
:sass
|
4
|
+
ol, li
|
5
|
+
list-style: number
|
6
|
+
li
|
7
|
+
height: 20px
|
8
|
+
width: 300px
|
9
|
+
margin-bottom: 4px
|
10
|
+
background: black
|
11
|
+
color: white
|
12
|
+
%ol#sortable
|
13
|
+
%li One: Lorem ipsum dolor sit amet
|
14
|
+
%li Two: Lorem ipsum dolor sit amet.
|
15
|
+
%li Three: Lorem ipsum dolor sit amet.
|
16
|
+
%li Four: Lorem ipsum dolor sit amet.
|
data/lib/jabs.rb
CHANGED
@@ -2,56 +2,19 @@ require 'fold'
|
|
2
2
|
require 'rack'
|
3
3
|
require 'johnson'
|
4
4
|
require 'pathname'
|
5
|
-
puts require Pathname.new(__FILE__).dirname.expand_path+'jabs/middleware'
|
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
5
|
|
52
6
|
module Jabs
|
53
|
-
|
7
|
+
def self.root
|
8
|
+
@root ||= Pathname.new(__FILE__).dirname.expand_path
|
9
|
+
end
|
10
|
+
|
11
|
+
require root+'jabs/precompiler'
|
12
|
+
require root+'jabs/engine'
|
13
|
+
require root+'jabs/middleware'
|
54
14
|
|
15
|
+
require root+'johnson/ext'
|
16
|
+
include Johnson::Nodes
|
17
|
+
|
55
18
|
def self.logger
|
56
19
|
@logger ||= begin
|
57
20
|
#TODO configurable logging
|
@@ -62,247 +25,5 @@ module Jabs
|
|
62
25
|
logger
|
63
26
|
end
|
64
27
|
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
28
|
|
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
29
|
end
|
307
|
-
|
308
|
-
puts Jabs::Engine.new($stdin.read).render if $0 == __FILE__
|
data/lib/jabs/engine.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Jabs
|
2
|
+
class Engine < Fold::Engine
|
3
|
+
def render context=nil
|
4
|
+
@p = precompiler_class.new
|
5
|
+
root = Johnson::Nodes::SourceElements.new 0, 0
|
6
|
+
main = Johnson::Nodes::SourceElements.new 0, 0
|
7
|
+
root << @p.johnsonize(@p.call([:function, nil, [], main]))
|
8
|
+
|
9
|
+
@p.fold(lines).children.each{|c|main << @p.johnsonize(c.render)}
|
10
|
+
root.to_ecma
|
11
|
+
rescue Fold::FoldFactory::IndentationError => e
|
12
|
+
require 'pp'
|
13
|
+
pp lines
|
14
|
+
puts "______------UP"
|
15
|
+
raise e
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/jabs/middleware.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
module Jabs
|
2
|
-
|
3
2
|
module Rack
|
3
|
+
|
4
|
+
def self.mount(rack_builder, mount_pount)
|
5
|
+
rack_builder.map(mount_pount) do
|
6
|
+
run (lambda do |env|
|
7
|
+
source = %w{
|
8
|
+
jquery/jquery-1.3.2.js
|
9
|
+
jquery/jquery.event.drag-1.5.js
|
10
|
+
jquery/jquery.event.drop-1.2.js
|
11
|
+
jquery/jquery.focus_and_blur.js
|
12
|
+
}.map{|path| (Jabs.root+path).read }.join("\n")
|
13
|
+
|
14
|
+
[200, {'Content-Type'=> 'text/javascript'}, source]
|
15
|
+
end)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
4
19
|
class Static < ::Rack::Static
|
5
20
|
def initialize(app, options={})
|
6
21
|
super(app, options)
|
@@ -11,7 +26,6 @@ module Jabs
|
|
11
26
|
|
12
27
|
class File < ::Rack::File
|
13
28
|
def serving
|
14
|
-
@path += ".jabs" unless @path[/\.jabs$/]
|
15
29
|
status, headers, body = * super
|
16
30
|
return [status, headers, body] unless status == 200
|
17
31
|
|
@@ -19,7 +33,7 @@ module Jabs
|
|
19
33
|
|
20
34
|
headers['Content-Type'] = 'text/javascript'
|
21
35
|
headers['Content-Length'] = jabs.size.to_s
|
22
|
-
|
36
|
+
|
23
37
|
[status, headers, jabs]
|
24
38
|
end
|
25
39
|
end
|