js2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,220 @@
1
+ class JS2::Test::SeleniumElement
2
+ attr_accessor :options
3
+ QUICK_WAIT_FOR = 5
4
+ AJAX_TIME_OUT = 60
5
+ def initialize (sel, klass, key, selector = nil)
6
+ @sel = sel
7
+ @key = key
8
+ @klass = klass
9
+ @selector = selector
10
+ end
11
+
12
+ def log (str)
13
+ if JS2::Test::Selenium.logger
14
+ JS2::Test::Selenium.logger.info(str)
15
+ end
16
+ end
17
+
18
+ def raw
19
+ ret = self.class.new(@sel, @klass, @key, @selector)
20
+ ret.options[:raw] = true
21
+ return ret
22
+ end
23
+
24
+ def check
25
+ return execute('checked=true')
26
+ end
27
+
28
+ def uncheck
29
+ return execute('checked=false')
30
+ end
31
+
32
+ def checked?
33
+ return execute('checked')
34
+ end
35
+
36
+ def execute (str)
37
+ wait_for_ajax
38
+ return @sel.execute(get_js_locator() + '.' + str)
39
+ end
40
+
41
+ def visible?(wait_for = nil)
42
+ return self.check_attribute(':visible', true, wait_for);
43
+ end
44
+
45
+ def sel_visible?()
46
+ return @sel.visible?(get_ele())
47
+ end
48
+
49
+ def hidden?(wait_for = nil)
50
+ return self.check_attribute(':visible', false, wait_for);
51
+ end
52
+
53
+ def find (str, idx = 0)
54
+ selector = "window.$(#{get_js_locator()}).find(#{str.to_json})[#{idx}]"
55
+ return self.class.new(@sel, @klass, @key, selector)
56
+ end
57
+
58
+ def filter (str, idx = 0)
59
+ selector = "window.$(#{get_js_locator()}).filter(#{str.to_json})[#{idx}]"
60
+ return self.class.new(@sel, @klass, @key, selector)
61
+ end
62
+
63
+ def get (idx)
64
+ # when jqObjects in //@+
65
+ selector = "#{get_js_locator()}[#{idx}][0]"
66
+ return self.class.new(@sel, @klass, @key, selector)
67
+ end
68
+
69
+ def [] (idx)
70
+ selector = "#{get_js_locator()}[#{idx}]"
71
+ return self.class.new(@sel, @klass, @key, selector)
72
+ end
73
+
74
+ def attr (attr)
75
+ get_ele()
76
+ js = %{return window.$(#{get_js_locator()}).attr(#{attr.to_json});}
77
+ return @sel.js_eval(js)
78
+ end
79
+
80
+ def check_attribute (attr, val, wait_for = nil)
81
+ wait_for ||= QUICK_WAIT_FOR
82
+ get_ele()
83
+ js = %{window.$(#{get_js_locator()}).is('#{attr}') == #{val.to_json};}
84
+ begin
85
+ log "Waiting for #{@key}.#{attr} to be #{val.to_json}... Waiting #{wait_for} secs."
86
+ @sel.wait_for_condition(js, wait_for)
87
+ rescue Selenium::CommandError
88
+ return false
89
+ end
90
+
91
+ return true
92
+ end
93
+
94
+ def containsp? (str)
95
+ wait_for_ajax
96
+ js = %{window.$(#{get_js_locator()}).html().toLowerCase().indexOf(#{str.to_json.downcase}) >= 0;}
97
+ begin
98
+ @sel.wait_for_condition(js, QUICK_WAIT_FOR)
99
+ return true
100
+ rescue Selenium::CommandError
101
+ return false
102
+ end
103
+ end
104
+
105
+ def contains? (str,timeout=QUICK_WAIT_FOR)
106
+ wait_for_ajax
107
+ js = %{window.$(#{get_js_locator()}).html().indexOf(#{str.to_json}) >= 0;}
108
+ begin
109
+ @sel.wait_for_condition(js, timeout)
110
+ return true
111
+ rescue Selenium::CommandError
112
+ return false
113
+ end
114
+ end
115
+
116
+ def click (options = {})
117
+ @sel.click(get_ele(), options)
118
+ end
119
+
120
+ def text
121
+ return @sel.text(get_ele())
122
+ end
123
+
124
+ def get_value
125
+ return @sel.get_value(get_ele())
126
+ end
127
+
128
+ def click! (options = {})
129
+ @sel.click(get_ele(), options)
130
+ @sel.wait_for_page
131
+ end
132
+
133
+ def mouse_up ()
134
+ trigger("LEFT_MOUSE_UP")
135
+ end
136
+
137
+ def mouse_down ()
138
+ trigger("LEFT_MOUSE_DOWN")
139
+ end
140
+
141
+ def mouse_over (options = {})
142
+ @sel.mouse_over(get_ele(), options)
143
+ end
144
+
145
+ def mouse_out (options = {})
146
+ @sel.mouse_out(get_ele(), options)
147
+ end
148
+
149
+ def type (*params)
150
+ elem = get_ele()
151
+ @sel.type(elem, *params)
152
+ @sel.fire_event(elem, 'blur')
153
+ end
154
+
155
+ def html ()
156
+ wait_for_ajax
157
+ js = get_js_locator()
158
+ return @sel.js_eval("#{js}.innerHTML;")
159
+ end
160
+
161
+ private
162
+
163
+ def get_locator
164
+ js = get_js_locator()
165
+ dom_locator = "dom=#{js};"
166
+ return dom_locator
167
+ end
168
+
169
+ def get_ele
170
+ real_locator = get_locator()
171
+ wait_for_ele()
172
+
173
+ return real_locator
174
+ end
175
+
176
+ def get_js_locator
177
+ if @selector
178
+ return @selector
179
+ end
180
+
181
+ filtered_locator = @key.to_s
182
+ int = ''
183
+
184
+ if m = filtered_locator.match(/([^\[\]]+)(\[([^\]]*)\])/)
185
+ log "filtered: #{filtered_locator} #{m.inspect}"
186
+ filtered_locator = m[1]
187
+ int = ', ' + m[3] if m[3]
188
+ end
189
+
190
+ funct = 'getVal'
191
+ get_val = "window.USE_SEL_MARKER.#{funct}('#{@klass}', '#{filtered_locator}'#{int})"
192
+
193
+ return get_val
194
+ end
195
+
196
+ def wait_for_ele ()
197
+ real_locator = get_locator
198
+ puts "waiting for #{real_locator}"
199
+ wait_for_ajax
200
+ @sel.wait_for_condition real_locator, QUICK_WAIT_FOR
201
+ puts "found #{real_locator}"
202
+ end
203
+
204
+ def wait_for_ajax
205
+ @sel.wait_for_condition('selenium.browserbot.getCurrentWindow().jQuery.active == 0', AJAX_TIME_OUT)
206
+ end
207
+
208
+ def trigger (event)
209
+ get_ele()
210
+ @sel.execute("window.$(#{get_js_locator}).trigger(JS2.SEL_EVENTS.#{event})")
211
+ end
212
+
213
+ def method_missing (method, *arg)
214
+ if @sel.respond_to?(method)
215
+ return @sel.send(method, get_js_locator, *arg)
216
+ else
217
+ raise "Method missing: #{method}"
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,27 @@
1
+ class JS2::Test::SeleniumHelper
2
+ attr_accessor :klass, :lookup
3
+
4
+ def initialize (klass, lookup, sel)
5
+ @klass = klass
6
+ @lookup = lookup
7
+ @sel = sel
8
+ @all_eles = Hash.new
9
+ end
10
+
11
+ def [] (key, tail = nil)
12
+ key = key.to_s
13
+
14
+ return @all_eles[key] if @all_eles[key]
15
+
16
+ # TODO: support inheritence
17
+ #raise "invalid key #{key}" unless @lookup[key]
18
+
19
+ return @all_eles[key] = JS2::Test::SeleniumElement.new(@sel, @klass, key, tail)
20
+ end
21
+
22
+ def type_form (params = {})
23
+ params.each_pair do |k,v|
24
+ self[k].type(v)
25
+ end
26
+ end
27
+ end
data/lib/js2.rb ADDED
@@ -0,0 +1,95 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Js2
5
+ VERSION = '0.0.1'
6
+ end
7
+
8
+ module JS2
9
+ module Parser
10
+ end
11
+ module AST
12
+ end
13
+ module Process
14
+ end
15
+ module Decorator
16
+ end
17
+ module Test
18
+ end
19
+
20
+ end
21
+
22
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
23
+
24
+ # for others
25
+ require 'js2/processor'
26
+ require 'js2/daemon'
27
+ require 'js2/config'
28
+
29
+ # parser
30
+ require 'js2/parser/fast'
31
+ require 'js2/parser/haml'
32
+
33
+ # process
34
+ require 'js2/process/haml_engine'
35
+ require 'js2/process/file_handler'
36
+ require 'js2/process/universe'
37
+
38
+ # ast
39
+ require 'js2/ast/node'
40
+ require 'js2/ast/class_node'
41
+ require 'js2/ast/comment_node'
42
+ require 'js2/ast/haml_node'
43
+ require 'js2/ast/inherited_node'
44
+ require 'js2/ast/stuff_node'
45
+ require 'js2/ast/member_node'
46
+ require 'js2/ast/method_node'
47
+ require 'js2/ast/module_node'
48
+ require 'js2/ast/include_node'
49
+ require 'js2/ast/nodes'
50
+
51
+ # decorator
52
+ require 'js2/decorator/standard'
53
+ require 'js2/decorator/test'
54
+ require 'js2/decorator/cleanser'
55
+
56
+ require 'yaml'
57
+
58
+ # test
59
+ require 'js2/test/selenium'
60
+ require 'js2/test/selenium_helper'
61
+ require 'js2/test/selenium_element'
62
+
63
+ module JS2
64
+ def self.config
65
+ return @@config
66
+ end
67
+
68
+ def self.config_file= (config_file)
69
+ @@config = YAML.load_file(config_file)
70
+ end
71
+
72
+ def self.write_files(params)
73
+ return self.daemon.run(1)
74
+ end
75
+
76
+ def self.daemon (params)
77
+ return JS2::Process::Daemon.new(params)
78
+ end
79
+
80
+ begin
81
+ # for haml filter
82
+ module JS2
83
+ include Haml::Filters::Base
84
+
85
+ def render (text)
86
+ parser = ::JS2::Parser::Fast.new
87
+ nodes = parser.parse_string(text)
88
+ decorator = ::JS2::Decorator::Test.new
89
+ return "<script>" + decorator.draw_nodes(nodes) + "</script>"
90
+ end
91
+ end
92
+ rescue Exception
93
+ puts "No haml filter support"
94
+ end
95
+ end
@@ -0,0 +1,9 @@
1
+ namespace :js2 do
2
+ task :build => :environment do
3
+ # normal stuff
4
+ CONFIG_FILE = "#{RAILS_ROOT}/config/js2.yml"
5
+ d = JS2::Processor.daemon_from_file(CONFIG_FILE, RAILS_ENV)
6
+ d.run(1)
7
+ end
8
+
9
+ end
@@ -0,0 +1,322 @@
1
+ # Somewhat based on http://www.mozilla.org/js/language/js20-2000-07/formal/lexer-grammar.html
2
+ # Regular Expression Literals determined with these rules:
3
+ # http://www.mozilla.org/js/language/js20-1999-03-25/tokens.html
4
+
5
+ %%{
6
+ machine dude;
7
+ alphtype char;
8
+
9
+ action actionStringBegin {
10
+ }
11
+
12
+ action actionStringAcc {
13
+ }
14
+
15
+ action actionStringAccBsEscape {
16
+ }
17
+
18
+ action actionStringAccUtf16 {
19
+ }
20
+
21
+ unicodecharacter = any;
22
+ unicodeinitialalphabetic = alpha;
23
+ unicodealphanumeric = alnum;
24
+ whitespacecharacter = [\t\v\f ];
25
+ lineterminator = ('\r' | '\n');
26
+ asciidigit = digit;
27
+
28
+ literals = (
29
+ '==' | '!=' | '===' | '!==' | '<=' | '>=' | '||' | '&&' | '++' | '--' | '<<' | '<<=' | '>>' | '>>=' | '>>>' | '>>>='| '&=' | '%=' | '^=' | '|=' | '+=' | '-=' | '*=' | '/='
30
+ );
31
+
32
+ # put in class
33
+ # put in accessor
34
+ keywords = (
35
+ 'break' | 'case' | 'catch' | 'continue' | 'default' | 'delete' | 'do' |
36
+ 'else' | 'finally' | 'for' | 'function' | 'if' | 'in' | 'instanceof' |
37
+ 'new' | 'return' | 'switch' | 'this' | 'throw' | 'try' | 'typeof' | 'var' | 'accessor' |
38
+ 'void' | 'while' | 'with' | 'const' | 'true' | 'false' | 'null' | 'debugger' |
39
+ 'class' | 'static' | 'foreach' | 'module' | 'include' | 'property'
40
+ );
41
+
42
+ # took out class
43
+ reserved = (
44
+ 'abstract' | 'boolean' | 'byte' | 'char' | 'double' | 'enum' | 'export' |
45
+ 'extends' | 'final' | 'float' | 'goto' | 'implements' | 'import' | 'int' | 'interface' |
46
+ 'long' | 'native' | 'package' | 'private' | 'protected' | 'public' | 'short' |
47
+ 'super' | 'synchronized' | 'throws' | 'transient' | 'volatile'
48
+ );
49
+
50
+ nonterminator = any - lineterminator;
51
+ linecommentcharacters = nonterminator*;
52
+ nonterminatororslash = nonterminator - '/';
53
+ nonterminatororastreisk = nonterminator - '*';
54
+ nonterminatororasteriskorslash = nonterminator - ('*' | '/');
55
+ blockcommentcharacters = (nonterminatororslash | (nonterminatororastreisk '/'))*;
56
+ multilineblockcommentcharacters = (blockcommentcharacters lineterminator)*;
57
+
58
+ linecomment = '//' linecommentcharacters;
59
+ singlelineblockcomment = '/*' blockcommentcharacters '*/';
60
+ multilineblockcomment = '/*' multilineblockcommentcharacters blockcommentcharacters '*/';
61
+ comment = linecomment | singlelineblockcomment | multilineblockcomment;
62
+
63
+ string_begin = '\'' @ actionStringBegin;
64
+ string_end = '\'';
65
+ stringchar_normal = ^(['\\] | 0..0x1f) @ actionStringAcc;
66
+ stringchar_bs_esc = '\\'['\\/bfnrt] @ actionStringAccBsEscape;
67
+ stringchar_utf16 = '\\u'[0-9a-fA-F]{4} @ actionStringAccUtf16;
68
+ stringchar_bs_other = '\\'^(['\\/bfnrtu]|0..0x1f) @ actionStringAccBsEscape;
69
+ stringchar = (stringchar_normal | stringchar_bs_esc | stringchar_utf16 | stringchar_bs_other);
70
+ string = string_begin . stringchar* . string_end;
71
+
72
+ ds_string_begin = '"' @ actionStringBegin;
73
+ ds_string_end = '"';
74
+ ds_stringchar_normal = ^(["\\] | 0..0x1f) @ actionStringAcc;
75
+ ds_stringchar_bs_esc = '\\'["\\/bfnrt] @ actionStringAccBsEscape;
76
+ ds_stringchar_utf16 = '\\u'[0-9a-fA-F]{4} @ actionStringAccUtf16;
77
+ ds_stringchar_bs_other = '\\'^(["\\/bfnrtu]|0..0x1f) @ actionStringAccBsEscape;
78
+ ds_stringchar = (ds_stringchar_normal | ds_stringchar_bs_esc | ds_stringchar_utf16 | ds_stringchar_bs_other);
79
+ ds_string = ds_string_begin . ds_stringchar* . ds_string_end;
80
+
81
+ all_string = string | ds_string;
82
+
83
+ integer = '-'? . digit+;
84
+ float = '-'? (
85
+ (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
86
+ | (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
87
+ );
88
+ number = integer | float;
89
+
90
+ identifier_char = ([a-zA-Z0-9_]) | '$';
91
+ identifier = identifier_char+;
92
+
93
+ ordinaryregexpchar = nonterminator - ('/' | '\\');
94
+ regexpchars = (ordinaryregexpchar | '\\' nonterminator)+;
95
+ regexpbody = '/' @ {regexp_start = p;} regexpchars '/';
96
+ regexpflags = ('g' | 'i' | 'm')*;
97
+ regexpliteral = regexpbody regexpflags;
98
+
99
+ specialcasedivide = (
100
+ identifier '/'
101
+ );
102
+ single_char = any;
103
+
104
+ arg_list = '(' . whitespacecharacter* . (identifier . whitespacecharacter* . ',' . whitespacecharacter*)* . identifier? . whitespacecharacter* . ')';
105
+ curry_with = 'with' . whitespacecharacter* . arg_list;
106
+ curry = 'curry' . whitespacecharacter* . arg_list? . whitespacecharacter* . curry_with? . whitespacecharacter* . '{';
107
+
108
+ main := |*
109
+
110
+ lineterminator => {
111
+ line_number++;
112
+ };
113
+
114
+ curry => {
115
+ curr = ts-data;
116
+ <%= replacer.start :CURRY %>
117
+ cb_count++;
118
+ };
119
+
120
+ whitespacecharacter => {};
121
+ comment => {
122
+ if (<%= replacer.directly_in? :CLASS %>) {
123
+ <%= replacer.do_next(:COMMENT, 'ts-data', 'te-data-1') %>
124
+ }
125
+ };
126
+
127
+ all_string => {};
128
+ number => {};
129
+ keywords => {
130
+ curr = ts-data;
131
+
132
+ <%= replacer.set_keyword %>
133
+
134
+ if (<%= replacer.is? :CLASS %> || <%= replacer.is? :MODULE %>) {
135
+ if (<%= replacer.is? :CLASS %>) {
136
+ <%= replacer.start :CLASS %>
137
+ } else {
138
+ <%= replacer.start :MODULE %>
139
+ }
140
+
141
+ // if "class" wasn't the first thing in the file
142
+ // then submit the :STUFF
143
+ if (curr > 0) {
144
+ <%= replacer.stop :STUFF, 'curr-1' %>
145
+ }
146
+
147
+ } else if (<%= replacer.directly_in? :CLASS %> || <%= replacer.directly_in? :MODULE %>) {
148
+ if (<%= replacer.is? :STATIC %>) {
149
+ <%= replacer.set_static %>
150
+ }
151
+
152
+ if (<%= replacer.is? :FUNCTION %>) {
153
+ <%= replacer.start :METHOD %>
154
+ }
155
+
156
+ if (<%= replacer.is? :VAR %>) {
157
+ <%= replacer.start :MEMBER %>
158
+ }
159
+
160
+
161
+ if (<%= replacer.is? :ACCESSOR %>) {
162
+ <%= replacer.start :MEMBER %>
163
+ }
164
+
165
+ if (<%= replacer.is? :PROPERTY %>) {
166
+ <%= replacer.start :PROPERTY %>
167
+ }
168
+
169
+
170
+ if (<%= replacer.is? :INCLUDE %>) {
171
+ <%= replacer.start :INCLUDE %>
172
+ }
173
+
174
+ }
175
+
176
+ if (<%= replacer.is? :FOREACH %>) {
177
+ <%= replacer.start :FOREACH %>
178
+ }
179
+
180
+ };
181
+
182
+ literals => { };
183
+ reserved => { };
184
+ identifier => { };
185
+
186
+ <%= replacer.def_literals %>
187
+
188
+ single_char | (('(' | '{' | ';') whitespacecharacter* regexpliteral) => {
189
+ curr = ts-data;
190
+ single = data[ts-data];
191
+
192
+ if (single == '(') {
193
+ br_count++;
194
+ } else if (single == ')') {
195
+ br_count--;
196
+
197
+ if (in_FOREACH && br_count == br_lvl_FOREACH) {
198
+ <%= replacer.stop :FOREACH %>
199
+ }
200
+ }
201
+
202
+ if (single == '{') {
203
+ cb_count++;
204
+ } else if (single == '}') {
205
+ if (<%= replacer.directly_in? :CLASS %> || <%= replacer.directly_in? :MODULE %>) {
206
+ <%= replacer.start :STUFF, 'curr+1' %>
207
+ }
208
+
209
+ cb_count--;
210
+
211
+ // stuff that stops on }'s
212
+ <%= replacer.handle_stops [ :METHOD, :CLASS, :FOREACH, :MODULE, :CURRY ] %>
213
+ }
214
+
215
+ if (single == ';') {
216
+ <%= replacer.handle_semicolon_stops [ :MEMBER, :INCLUDE, :PROPERTY ] %>
217
+ }
218
+
219
+ };
220
+
221
+ *|;
222
+ }%%
223
+
224
+ require 'rubygems'
225
+ require 'inline'
226
+
227
+ class JS2::Parser::Fast
228
+ attr_accessor :data
229
+
230
+ inline do |builder|
231
+ builder.c_raw <<-END
232
+
233
+ int do_parse (int argc, VALUE *argv, VALUE self) {
234
+ // convert ruby string to char*
235
+ VALUE r_str = argv[0];
236
+ int data_length = RSTRING(r_str)->len;
237
+ char* data = STR2CSTR(r_str);
238
+
239
+ VALUE ln_argv[1];
240
+ int ln_argc = 1;
241
+ int line_number = 1;
242
+ ID ln_sym = rb_intern("set_line_number");
243
+
244
+ // do_next vars
245
+ VALUE do_next_argv[4];
246
+ int do_next_argc = 4;
247
+ ID do_next_sym = rb_intern("do_next");
248
+
249
+ VALUE set_static_argv[0];
250
+ int set_static_argc = 0;
251
+ ID set_static_sym = rb_intern("set_static");
252
+
253
+ // state vars
254
+ int i = 0; // iterator
255
+ int j = 0; // iterator
256
+ char word[100]; // keyword
257
+ char single;
258
+
259
+ int curr = 0;
260
+ int prev = -1;
261
+ int cb_count = 0;
262
+ int br_count = 0;
263
+
264
+ <%= replacer.declare_vars [ :CLASS, :METHOD, :MEMBER, :STUFF, :ACCESSOR, :COMMENT, :FOREACH, :MODULE, :INCLUDE, :CURRY, :PROPERTY ] %>
265
+
266
+ // ragel variables
267
+ int cs, act;
268
+ char *ts = NULL;
269
+ char *te = NULL;
270
+ char *p = data;
271
+ char *pe = p + data_length;
272
+ char *eof = pe;
273
+ char* regexp_start = NULL;
274
+
275
+ <%= replacer.start :STUFF %>
276
+
277
+ %% write data;
278
+ %% write init;
279
+ %% write exec;
280
+
281
+ if (in_STUFF == 1) {
282
+ <%= replacer.stop :STUFF %>
283
+ }
284
+ }
285
+
286
+ END
287
+ end
288
+
289
+ def set_line_number (l)
290
+ @line_number = l
291
+ end
292
+
293
+ def set_static ()
294
+ @nodes.set_static
295
+ end
296
+
297
+ def do_next (symbol, start_idx, end_idx, line)
298
+ if end_idx == -1 then end_idx = start_idx end
299
+ @nodes.do_next(symbol, start_idx, end_idx, line)
300
+ end
301
+
302
+ def parse_string (str)
303
+ self.data = str
304
+ @nodes = JS2::AST::Nodes.new("string", str)
305
+ self.do_parse(str)
306
+ return @nodes
307
+ end
308
+
309
+ def parse(filename)
310
+ self.data = File.read(filename)
311
+ @nodes = JS2::AST::Nodes.new(filename, data)
312
+
313
+ #@cleanser ||= JS2::DecoCleanser.new
314
+ #@cleanser.cleanse(data)
315
+
316
+ eof = data.size
317
+ self.do_parse(data)
318
+
319
+ return @nodes
320
+ end
321
+
322
+ end