opal-irb 0.7.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 +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +113 -0
- data/Guardfile +5 -0
- data/LICENSE +21 -0
- data/README.md +175 -0
- data/Rakefile +65 -0
- data/Roadmap.org +17 -0
- data/app/assets/stylesheets/opal-irb/jqconsole.css +263 -0
- data/compiled/app-embeddable.js +39765 -0
- data/compiled/app-jqconsole.js +39767 -0
- data/compiled/application.js +27399 -0
- data/css/ansi.css +172 -0
- data/css/opal_irb_jqconsole.css +79 -0
- data/css/show-hint.css +38 -0
- data/doc/presentations/opal_irb_overview.html +678 -0
- data/doc/presentations/opal_irb_overview.org +448 -0
- data/examples/app-embeddable.rb +8 -0
- data/examples/app-jqconsole.rb +10 -0
- data/examples/application.rb +8 -0
- data/index-embeddable.html +29 -0
- data/index-homebrew.html +115 -0
- data/index-jq.html +80 -0
- data/js/anyword-hint.js +44 -0
- data/js/jqconsole.js +1583 -0
- data/js/nodeutil.js +546 -0
- data/js/ruby.js +285 -0
- data/js/show-hint.js +383 -0
- data/lib/opal-irb/rails_engine.rb +3 -0
- data/lib/opal-irb/version.rb +3 -0
- data/lib/opal-irb-rails.rb +2 -0
- data/lib/opal-irb.rb +44 -0
- data/opal/object_extensions.rb +20 -0
- data/opal/opal_irb/completion_engine.rb +202 -0
- data/opal/opal_irb/completion_formatter.rb +49 -0
- data/opal/opal_irb/completion_results.rb +88 -0
- data/opal/opal_irb.rb +88 -0
- data/opal/opal_irb_homebrew_console.rb +398 -0
- data/opal/opal_irb_jqconsole.rb +517 -0
- data/opal/opal_irb_jqconsole_css.rb +259 -0
- data/opal/opal_irb_log_redirector.rb +32 -0
- data/opal/opal_phantomjs.rb +49 -0
- data/opal-irb.gemspec +20 -0
- data/spec/code_link_handler_spec.rb +30 -0
- data/spec/jquery.js +5 -0
- data/spec/object_extensions_spec.rb +32 -0
- data/spec/opal_irb/completion_engine_spec.rb +204 -0
- data/spec/opal_irb/completion_results_spec.rb +32 -0
- data/spec/opal_irb_log_director_spec.rb +19 -0
- data/spec/opal_irb_spec.rb +19 -0
- data/spec/spec_helper.rb +1 -0
- metadata +151 -0
data/lib/opal-irb.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'opal'
|
2
|
+
require 'opal-jquery'
|
3
|
+
require 'opal-irb/version.rb'
|
4
|
+
Opal.append_path File.expand_path('../../opal', __FILE__)
|
5
|
+
Opal.append_path File.expand_path('../../js', __FILE__)
|
6
|
+
|
7
|
+
module OpalIrbUtils
|
8
|
+
|
9
|
+
# used to include the requirements in a template file ala
|
10
|
+
# <%= OpalIrbUtils.include_opal_irb_jqconsole_requirements %>
|
11
|
+
# params opts[:include_jquery] include a canned version of jquery, jquery-ui, jquery-migrate that is compatibable w/the jqconsole. Set this to false if you already include these files
|
12
|
+
# params opts[:include_codemirror] include the code mirror
|
13
|
+
def self.include_opal_irb_jqconsole_requirements(opts = { :include_jquery => true, :include_codemirror => true})
|
14
|
+
jquery_scripts = opts[:include_jquery] ? include_web_jquery : ""
|
15
|
+
code_mirror_scripts = opts[:include_codemirror] ? include_code_mirror : ""
|
16
|
+
|
17
|
+
jquery_scripts + code_mirror_scripts
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.include_web_jquery
|
21
|
+
jquery_requirements = [
|
22
|
+
"http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js",
|
23
|
+
"https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js",
|
24
|
+
"http://code.jquery.com/jquery-migrate-1.2.1.js"
|
25
|
+
]
|
26
|
+
# style sheet so editor window has styling
|
27
|
+
'<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />' +
|
28
|
+
require_scripts(jquery_requirements)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.require_scripts(javascripts)
|
32
|
+
javascripts.map { |js|
|
33
|
+
"<script src='#{js}'></script>"
|
34
|
+
}.join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.include_code_mirror
|
38
|
+
'<link rel="stylesheet" href="//codemirror.net/lib/codemirror.css"/>' +
|
39
|
+
require_scripts( [ "//codemirror.net/lib/codemirror.js",
|
40
|
+
"//codemirror.net/keymap/emacs.js",
|
41
|
+
"//codemirror.net/mode/ruby/ruby.js"])
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# monkey patch object to get some stuff we want
|
2
|
+
class Object
|
3
|
+
def irb_instance_variables
|
4
|
+
filtered = ["@constructor", "@toString"]
|
5
|
+
instance_variables.reject {|var| filtered.include?(var)}.sort
|
6
|
+
end
|
7
|
+
|
8
|
+
def irb_instance_var_values
|
9
|
+
irb_instance_variables.map {|var_name| [var_name, instance_variable_get("#{var_name}")]}
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
# test class
|
15
|
+
class Foo
|
16
|
+
def initialize
|
17
|
+
@a = "a"
|
18
|
+
@b = "b"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
$CE_DEBUG = false # override to turn on debugging
|
2
|
+
require_relative 'completion_results'
|
3
|
+
class OpalIrb
|
4
|
+
# CompletionEngine for tab completes
|
5
|
+
class CompletionEngine
|
6
|
+
VARIABLE_DOT_COMPLETE = /(\s*([$]*\w+)\.)$/
|
7
|
+
METHOD_COMPLETE = /(\s*([$]*\w+)\.(\w+))$/
|
8
|
+
CONSTANT = /(\s*([A-Z]\w*))$/
|
9
|
+
METHOD_OR_VARIABLE = /(\s*([a-z]\w*))$/
|
10
|
+
GLOBAL = /(\s*\$(\w*))$/
|
11
|
+
|
12
|
+
NO_MATCHES_PARAMS = [nil, []]
|
13
|
+
# Shows completions for text in opal-irb
|
14
|
+
# @param text [String] the text to try to find completions for
|
15
|
+
# @returns [CompletionResults]
|
16
|
+
|
17
|
+
def self.complete(text, irb)
|
18
|
+
index, matches = get_matches(text, irb)
|
19
|
+
CompletionResults.new(text, index, matches)
|
20
|
+
end
|
21
|
+
# Editor complete, intended to be called from CodeMirror or other
|
22
|
+
# javascript editor that does not have the ability to see into
|
23
|
+
# Opal objects w/o some work. To use this, you must first
|
24
|
+
# set_irb() the irb you will be using
|
25
|
+
# @params text [String] the text to try to find completions for
|
26
|
+
# @returns [String[]] the matches
|
27
|
+
def self.editor_complete(text)
|
28
|
+
debug_puts "Getting matches for #{text}"
|
29
|
+
index, matches = get_matches(text, get_irb)
|
30
|
+
debug_puts "\tMatches = #{matches.inspect}"
|
31
|
+
matches || []
|
32
|
+
end
|
33
|
+
|
34
|
+
# For use with CodeMirror autocompletion, or anything that needs persistent irb
|
35
|
+
# of interacts through javascript
|
36
|
+
# @param irb [OpalIrb] the irb engine to use, typically that of an OpalIrb condole
|
37
|
+
def self.set_irb irb
|
38
|
+
@irb = irb
|
39
|
+
end
|
40
|
+
# Called by self.editor_complete to get the irb that is set
|
41
|
+
def self.get_irb
|
42
|
+
if @irb
|
43
|
+
@irb
|
44
|
+
else
|
45
|
+
raise "You must set irb to use this funtion"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def self.get_matches(text, irb)
|
49
|
+
index, matches = case text
|
50
|
+
when GLOBAL
|
51
|
+
debug_puts 'GLOBAL'
|
52
|
+
global_complete(text, irb)
|
53
|
+
when VARIABLE_DOT_COMPLETE
|
54
|
+
debug_puts 'VARIABLE_DOT_COMPLETE'
|
55
|
+
variable_dot_complete(text, irb)
|
56
|
+
when METHOD_COMPLETE
|
57
|
+
debug_puts 'METHOD_COMPLETE'
|
58
|
+
method_complete(text, irb)
|
59
|
+
when CONSTANT
|
60
|
+
debug_puts 'CONSTANT'
|
61
|
+
constant_complete(text, irb)
|
62
|
+
when METHOD_OR_VARIABLE
|
63
|
+
debug_puts 'METHOD_OR_VARIABLE'
|
64
|
+
method_or_variable_complete(text, irb)
|
65
|
+
else
|
66
|
+
NO_MATCHES_PARAMS
|
67
|
+
end
|
68
|
+
[index, matches]
|
69
|
+
end
|
70
|
+
def self.variable_dot_complete(text, irb)
|
71
|
+
index = text =~ VARIABLE_DOT_COMPLETE # broken in 0.7, fixed in 0.7
|
72
|
+
whole = $1
|
73
|
+
target_name = $2
|
74
|
+
get_correct_methods_by_type(whole, target_name, index, irb)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.get_correct_methods_by_type(whole, target_name, index, irb)
|
78
|
+
case target_name
|
79
|
+
when /^[A-Z]/
|
80
|
+
get_class_methods(whole, target_name, index)
|
81
|
+
when /^\$/
|
82
|
+
get_global_methods(whole, target_name, index, irb)
|
83
|
+
else
|
84
|
+
get_var_methods(whole, target_name, index, irb)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.get_class_methods(whole, target_name, index)
|
89
|
+
begin
|
90
|
+
klass = Kernel.const_get(target_name)
|
91
|
+
debug_puts "\t#{klass.inspect} #{klass.methods}"
|
92
|
+
[whole.size + index, klass.methods]
|
93
|
+
rescue
|
94
|
+
puts "\t RESCUE"
|
95
|
+
NO_MATCHES_PARAMS
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.get_global_methods(whole, target_name, index, irb)
|
100
|
+
debug_puts "get_global_methods(#{whole}, #{target_name}, #{index})"
|
101
|
+
target_name = target_name[1..-1] # strip off leading $
|
102
|
+
name_val_pair = irb.irb_gvars.find { |array| array[0] == target_name }
|
103
|
+
if name_val_pair
|
104
|
+
methods = name_val_pair[1].methods
|
105
|
+
return [whole.size + index, methods]
|
106
|
+
end
|
107
|
+
NO_MATCHES_PARAMS
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.get_var_methods(whole, target_name, index, irb)
|
111
|
+
name_val_pair = irb.irb_vars.find { |array| array[0] == target_name }
|
112
|
+
if name_val_pair
|
113
|
+
methods = name_val_pair[1].methods
|
114
|
+
return [whole.size + index, methods]
|
115
|
+
end
|
116
|
+
NO_MATCHES_PARAMS
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.method_complete(text, irb)
|
120
|
+
index = text =~ METHOD_COMPLETE # broken in 0.7, fixed in 0.7
|
121
|
+
whole = $1
|
122
|
+
target_name = $2
|
123
|
+
method_fragment = $3
|
124
|
+
get_matches_for_correct_type(whole, target_name, method_fragment, index, irb)
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.get_matches_for_correct_type(whole, target_name, method_fragment, index, irb)
|
128
|
+
debug_puts("get_matches_for_correct_type(#{whole}, #{target_name}, #{method_fragment}, #{index})")
|
129
|
+
case target_name
|
130
|
+
when /^[A-Z]/
|
131
|
+
get_class_methods_by_fragment(whole, target_name, method_fragment, index)
|
132
|
+
when /^\$/
|
133
|
+
get_global_methods_by_fragment(whole, target_name, method_fragment, index, irb)
|
134
|
+
else
|
135
|
+
get_var_methods_by_fragment(whole, target_name, method_fragment, index, irb)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.get_class_methods_by_fragment(whole, target_name, method_fragment, index)
|
140
|
+
debug_puts "get_class_methods_by_fragment whole: #{whole}, target_name: #{target_name}, method_fragment: #{method_fragment}, index"
|
141
|
+
begin
|
142
|
+
klass = Kernel.const_get(target_name)
|
143
|
+
debug_puts "\t#{klass.inspect} #{klass.methods}"
|
144
|
+
[whole.size + index - method_fragment.size, klass.methods.grep(/^#{method_fragment}/)]
|
145
|
+
rescue
|
146
|
+
puts "\t RESCUE"
|
147
|
+
NO_MATCHES_PARAMS
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.get_global_methods_by_fragment(whole, target_name, method_fragment, index, irb)
|
152
|
+
debug_puts "get_global_methods_by_fragment whole: #{whole}, target_name: #{target_name}, method_fragment: #{method_fragment}, index"
|
153
|
+
target_name = target_name[1..-1] # strip off leading $
|
154
|
+
name_val_pair = irb.irb_gvars.find { |array| array[0] == target_name }
|
155
|
+
if name_val_pair
|
156
|
+
methods = name_val_pair[1].methods.grep /^#{method_fragment}/
|
157
|
+
return [whole.size + index - method_fragment.size, methods]
|
158
|
+
end
|
159
|
+
NO_MATCHES_PARAMS
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.get_var_methods_by_fragment(whole, target_name, method_fragment, index, irb)
|
163
|
+
debug_puts "get_var_methods_by_fragment whole: #{whole}, target_name: #{target_name}, method_fragment: #{method_fragment}, index"
|
164
|
+
name_val_pair = irb.irb_vars.find { |array| array[0] == target_name }
|
165
|
+
if name_val_pair
|
166
|
+
methods = name_val_pair[1].methods.grep /^#{method_fragment}/
|
167
|
+
return [whole.size + index - method_fragment.size, methods]
|
168
|
+
end
|
169
|
+
NO_MATCHES_PARAMS
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.constant_complete(text, irb)
|
173
|
+
index = text =~ CONSTANT
|
174
|
+
whole = $1
|
175
|
+
fragment = $2
|
176
|
+
[whole.size + index - fragment.size, Object.constants.grep( /^#{fragment}/)]
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.method_or_variable_complete(text, irb)
|
180
|
+
index = text =~ METHOD_OR_VARIABLE
|
181
|
+
whole = $1
|
182
|
+
fragment = $2
|
183
|
+
varnames = irb.irb_varnames.grep /^#{fragment}/
|
184
|
+
matching_methods = methods.grep /^#{fragment}/
|
185
|
+
[whole.size + index - fragment.size, varnames + matching_methods]
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.global_complete(text, irb)
|
189
|
+
index = text =~ GLOBAL
|
190
|
+
whole = $1
|
191
|
+
fragment = $2
|
192
|
+
debug_puts "looking for |#{fragment}| from |#{text}|"
|
193
|
+
varnames = irb.irb_gvarnames.grep /^#{fragment}/
|
194
|
+
[whole.size + index - fragment.size - 1, varnames.map { |name| "$#{name}" }]
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.debug_puts stuff
|
198
|
+
puts(stuff) if $CE_DEBUG # completion_engine debug
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Array
|
2
|
+
def in_groups_of(number, fill_with = nil)
|
3
|
+
if number.to_i <= 0
|
4
|
+
raise ArgumentError,
|
5
|
+
"Group size must be a positive integer, was #{number.inspect}"
|
6
|
+
end
|
7
|
+
|
8
|
+
if fill_with == false
|
9
|
+
collection = self
|
10
|
+
else
|
11
|
+
# size % number gives how many extra we have;
|
12
|
+
# subtracting from number gives how many to add;
|
13
|
+
# modulo number ensures we don't add group of just fill.
|
14
|
+
padding = (number - size % number) % number
|
15
|
+
collection = dup.concat(Array.new(padding, fill_with))
|
16
|
+
end
|
17
|
+
|
18
|
+
if block_given?
|
19
|
+
collection.each_slice(number) { |slice| yield(slice) }
|
20
|
+
else
|
21
|
+
collection.each_slice(number).to_a
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class OpalIrb
|
27
|
+
# format completion in columns, like MRI irb
|
28
|
+
class CompletionFormatter
|
29
|
+
def self.format(choices)
|
30
|
+
new.format(choices)
|
31
|
+
end
|
32
|
+
|
33
|
+
def format(choices, width=80)
|
34
|
+
max_length = choices.inject(0) { |length, element| element.size > length ? element.size : length}
|
35
|
+
num_cols = (width/(max_length+1)).floor # coz this is JS
|
36
|
+
|
37
|
+
if max_length * num_cols == width
|
38
|
+
num_cols -= 1
|
39
|
+
end
|
40
|
+
|
41
|
+
column_width = max_length + ((width - (max_length * num_cols))/num_cols).floor
|
42
|
+
|
43
|
+
groups = choices.sort.in_groups_of(num_cols, false)
|
44
|
+
groups.map { |grouping| grouping.map { |choice| sprintf("%-#{column_width}s", choice) }.join }.join("\n") + "\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class OpalIrb
|
2
|
+
# Used to store results and perform the correct actions on the console
|
3
|
+
# 3 cases:
|
4
|
+
# * No match
|
5
|
+
# * no change to prompt
|
6
|
+
# * insert_tab == true
|
7
|
+
# * There is a single match
|
8
|
+
# * change prompt to the single match
|
9
|
+
# * insert_tab == false
|
10
|
+
# * There are multiple matches
|
11
|
+
# * show the matches
|
12
|
+
# * change prompt to the max common prefix
|
13
|
+
# * insert_tab == false
|
14
|
+
class CompletionResults
|
15
|
+
|
16
|
+
attr_reader :matches, :old_prompt, :new_prompt_text
|
17
|
+
def initialize(orig_text, match_index, matches)
|
18
|
+
@matches = matches || [] # Native#methods is nil, need to figure out how to handle it
|
19
|
+
# @insert_tab = matches.size > 0 ? false : true
|
20
|
+
@insert_tab = false
|
21
|
+
|
22
|
+
CompletionEngine.debug_puts "orig_text: |#{orig_text}| match_index: #{match_index} matches #{matches.inspect}"
|
23
|
+
if matches.size == 1
|
24
|
+
@new_prompt_text = match_index == 0 ? matches.first : "#{orig_text[0..match_index-1]}#{matches.first}"
|
25
|
+
elsif matches.size > 1
|
26
|
+
@old_prompt = orig_text
|
27
|
+
@new_prompt_text = common_prefix_if_exists(orig_text, match_index, matches)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def common_prefix_if_exists(orig_text, match_index, results)
|
32
|
+
working_copy = results.clone
|
33
|
+
first_word = working_copy.shift
|
34
|
+
chars = []
|
35
|
+
i = 0
|
36
|
+
# first_word.each_char { |char|
|
37
|
+
letters = [] #- break is broken on 0.8.0 beta for each_char
|
38
|
+
first_word.each_char { |char| letters << char }
|
39
|
+
letters.each { |char|
|
40
|
+
if working_copy.all? { |str| str[i] == char }
|
41
|
+
chars << char
|
42
|
+
i += 1
|
43
|
+
else
|
44
|
+
break
|
45
|
+
end
|
46
|
+
}
|
47
|
+
common = chars.join
|
48
|
+
CompletionEngine.debug_puts "\torig_text: |#{orig_text}| common prefix: #{common} match_index: #{match_index}"
|
49
|
+
match_index == 0 ? common : orig_text[0..match_index-1] + common
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def old_prompt?
|
54
|
+
@old_prompt
|
55
|
+
end
|
56
|
+
|
57
|
+
def matches?
|
58
|
+
@matches.size > 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def new_prompt?
|
62
|
+
@new_prompt_text
|
63
|
+
end
|
64
|
+
|
65
|
+
# Tells the console whether or not to tab or not
|
66
|
+
def insert_tab?
|
67
|
+
@insert_tab
|
68
|
+
end
|
69
|
+
# writes an "old prompt" before showing matchings results, if there are matches
|
70
|
+
# @param jqconsole [Native] jq-console used by opal-irb
|
71
|
+
# @param jqconsole [String] the old class
|
72
|
+
def set_old_prompt(jqconsole, prompt, jqconsole_class)
|
73
|
+
jqconsole.Write("#{prompt}#{old_prompt}\n", jqconsole_class) if old_prompt?
|
74
|
+
end
|
75
|
+
# Displays matches if there are any
|
76
|
+
# @param jqconsole [Native] jq-console used by opal-irb
|
77
|
+
def display_matches(jqconsole)
|
78
|
+
jqconsole.Write(OpalIrb::CompletionFormatter.format(matches)) if matches?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Updates the prompt to include the only match or most common prefix if there are any
|
82
|
+
# @param jqconsole [Native] jq-console used by opal-irb
|
83
|
+
def update_prompt(jqconsole)
|
84
|
+
jqconsole.SetPromptText(new_prompt_text) if new_prompt?
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/opal/opal_irb.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'opal'
|
2
|
+
require 'opal/compiler'
|
3
|
+
require 'object_extensions'
|
4
|
+
require 'opal-parser' # so I can have require_remote
|
5
|
+
|
6
|
+
# 'require' a javascript filename over the internet, asynchronously,
|
7
|
+
# so you'll have to delay before using. Should be fine if typed by hand
|
8
|
+
# but if scripted add delay
|
9
|
+
def require_js(url)
|
10
|
+
# used to use this, but don't want to depend on opal-jquery
|
11
|
+
# Element.find("head").append("<script src='#{js_filename}' type='text/javascript'></script>")
|
12
|
+
%x|
|
13
|
+
var script = document.createElement( 'script' );
|
14
|
+
script.type = 'text/javascript';
|
15
|
+
script.src = url;
|
16
|
+
document.body.appendChild(script);
|
17
|
+
|
|
18
|
+
end
|
19
|
+
|
20
|
+
# 'require' a javascrit filename over the internet, synchronously.
|
21
|
+
# Chrome complains that this is deprecated, so it might go away
|
22
|
+
def require_js_sync(url)
|
23
|
+
%x|
|
24
|
+
var r = new XMLHttpRequest();
|
25
|
+
r.open("GET", url, false);
|
26
|
+
r.send('');
|
27
|
+
window.eval(r.responseText)
|
28
|
+
|
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
class OpalIrb
|
33
|
+
def irb_vars
|
34
|
+
%x|irbVars = [];
|
35
|
+
for(variable in Opal.irb_vars) {
|
36
|
+
if(Opal.irb_vars.hasOwnProperty(variable)) {
|
37
|
+
irbVars.push([variable, Opal.irb_vars[variable]])
|
38
|
+
}
|
39
|
+
};
|
40
|
+
return irbVars;|
|
41
|
+
end
|
42
|
+
|
43
|
+
def irb_varnames
|
44
|
+
irb_vars.map { |varname, value| varname }
|
45
|
+
end
|
46
|
+
|
47
|
+
def irb_gvars
|
48
|
+
%x|gvars = [];
|
49
|
+
for(variable in Opal.gvars) {
|
50
|
+
if(Opal.gvars.hasOwnProperty(variable)) {
|
51
|
+
gvars.push([variable, Opal.gvars[variable]])
|
52
|
+
}
|
53
|
+
};
|
54
|
+
return gvars;|
|
55
|
+
end
|
56
|
+
|
57
|
+
def irb_gvarnames
|
58
|
+
irb_gvars.map { |varname, value| varname }
|
59
|
+
end
|
60
|
+
|
61
|
+
def opal_classes
|
62
|
+
classes = []
|
63
|
+
$opal_js_object = Native(`Opal`) # have to make this global right now coz not seen in the each closure w/current opal
|
64
|
+
$opal_js_object.each {|k|
|
65
|
+
attr = $opal_js_object[k]
|
66
|
+
classes << attr if attr.is_a?(Class)
|
67
|
+
}
|
68
|
+
classes.uniq.sort_by { |cls| cls.name } # coz some Opal classes are the same, i.e. module == class, base, Kernel = Object
|
69
|
+
end
|
70
|
+
|
71
|
+
def opal_constants
|
72
|
+
constants = []
|
73
|
+
$opal_js_object = Native(`Opal`) # have to make this global right now coz not seen in the each closure w/current opal
|
74
|
+
$opal_js_object.each {|k|
|
75
|
+
attr = $opal_js_object[k]
|
76
|
+
constants << attr
|
77
|
+
}
|
78
|
+
constants.uniq
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
attr_reader :parser
|
83
|
+
|
84
|
+
def parse(cmd)
|
85
|
+
Opal::Compiler.new(cmd, irb: true).compile
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|