opal 0.3.43 → 0.3.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG.md +19 -0
  2. data/README.md +1 -0
  3. data/Rakefile +29 -19
  4. data/examples/native/Gemfile +3 -0
  5. data/examples/native/README.md +17 -0
  6. data/examples/native/app/app.rb +38 -0
  7. data/examples/native/config.ru +8 -0
  8. data/examples/native/index.html.erb +12 -0
  9. data/lib/opal/lexer.rb +5 -1
  10. data/lib/opal/parser.rb +36 -10
  11. data/lib/opal/processor.rb +10 -9
  12. data/lib/opal/server.rb +17 -7
  13. data/lib/opal/target_scope.rb +2 -2
  14. data/lib/opal/version.rb +1 -1
  15. data/opal/opal-browser/script_loader.rb +8 -13
  16. data/opal/opal.rb +23 -5
  17. data/opal/opal/array.rb +128 -14
  18. data/opal/opal/boolean.rb +1 -1
  19. data/opal/opal/class.rb +92 -18
  20. data/opal/opal/enumerable.rb +90 -0
  21. data/opal/opal/error.rb +1 -1
  22. data/opal/opal/hash.rb +2 -2
  23. data/opal/opal/kernel.rb +3 -3
  24. data/opal/opal/numeric.rb +1 -1
  25. data/opal/opal/proc.rb +1 -1
  26. data/opal/opal/regexp.rb +31 -31
  27. data/opal/opal/runtime.js +181 -69
  28. data/opal/opal/string.rb +561 -40
  29. data/opal/opal/time.rb +1 -1
  30. data/opal/rbconfig.rb +17 -3
  31. data/opal/strscan.rb +41 -5
  32. data/spec/opal/class/new_spec.rb +27 -0
  33. data/spec/opal/native_spec.rb +127 -0
  34. data/spec/ospec/runner.rb +0 -2
  35. data/spec/parser/strscan/get_byte_spec.rb +29 -0
  36. data/spec/parser/strscan/skip_spec.rb +40 -0
  37. data/spec/rubyspec/core/array/each_spec.rb +1 -1
  38. data/spec/rubyspec/core/array/intersection_spec.rb +5 -0
  39. data/spec/rubyspec/core/array/max_spec.rb +32 -0
  40. data/spec/rubyspec/core/array/min_spec.rb +32 -0
  41. data/spec/rubyspec/core/array/minus_spec.rb +7 -5
  42. data/spec/rubyspec/core/array/multiply_spec.rb +1 -1
  43. data/spec/rubyspec/core/array/plus_spec.rb +1 -1
  44. data/spec/rubyspec/core/array/pop_spec.rb +1 -1
  45. data/spec/rubyspec/core/array/push_spec.rb +1 -1
  46. data/spec/rubyspec/core/array/rassoc_spec.rb +1 -1
  47. data/spec/rubyspec/core/array/reject_spec.rb +2 -2
  48. data/spec/rubyspec/core/array/reverse_each_spec.rb +2 -2
  49. data/spec/rubyspec/core/array/rindex_spec.rb +2 -2
  50. data/spec/rubyspec/core/array/select_spec.rb +1 -1
  51. data/spec/rubyspec/core/array/shift_spec.rb +1 -1
  52. data/spec/rubyspec/core/array/slice_spec.rb +1 -1
  53. data/spec/rubyspec/core/array/sort_spec.rb +15 -15
  54. data/spec/rubyspec/core/array/to_a_spec.rb +1 -1
  55. data/spec/rubyspec/core/array/to_ary_spec.rb +1 -1
  56. data/spec/rubyspec/core/array/uniq_spec.rb +1 -1
  57. data/spec/rubyspec/core/array/unshift_spec.rb +1 -1
  58. data/spec/rubyspec/core/array/zip_spec.rb +1 -1
  59. data/spec/rubyspec/core/enumerable/select_spec.rb +4 -1
  60. data/spec/rubyspec/core/module/const_defined_spec.rb +86 -0
  61. data/spec/rubyspec/core/module/const_get_spec.rb +55 -3
  62. data/spec/rubyspec/core/module/const_set_spec.rb +2 -2
  63. data/spec/rubyspec/core/module/constants_spec.rb +49 -0
  64. data/spec/rubyspec/core/regexp/match_spec.rb +66 -1
  65. data/spec/rubyspec/core/string/center_spec.rb +71 -0
  66. data/spec/rubyspec/core/string/chomp_spec.rb +6 -1
  67. data/spec/rubyspec/core/string/clone_spec.rb +8 -0
  68. data/spec/rubyspec/core/string/dup_spec.rb +8 -0
  69. data/spec/rubyspec/core/string/end_with_spec.rb +5 -1
  70. data/spec/rubyspec/core/string/gsub_spec.rb +15 -1
  71. data/spec/rubyspec/core/string/lines_spec.rb +9 -0
  72. data/spec/rubyspec/core/string/ljust_spec.rb +17 -0
  73. data/spec/rubyspec/core/string/match_spec.rb +25 -3
  74. data/spec/rubyspec/core/string/rindex_spec.rb +50 -0
  75. data/spec/rubyspec/core/string/rjust_spec.rb +17 -0
  76. data/spec/rubyspec/core/string/scan_spec.rb +66 -0
  77. data/spec/rubyspec/core/string/sub_spec.rb +17 -1
  78. data/spec/rubyspec/core/string/tr_s_spec.rb +31 -0
  79. data/spec/rubyspec/core/string/tr_spec.rb +31 -0
  80. data/spec/rubyspec/fixtures/constants.rb +6 -0
  81. data/spec/rubyspec/language/class_spec.rb +4 -8
  82. data/spec/rubyspec/language/numbers_spec.rb +10 -4
  83. data/spec/rubyspec/language/predefined_spec.rb +69 -2
  84. data/spec/rubyspec/library/rbconfig/config_spec.rb +47 -0
  85. data/spec/rubyspec/spec_helper.rb +6 -0
  86. metadata +46 -25
  87. data/opal/opal-eventable.rb +0 -26
  88. data/opal/opal/native.rb +0 -115
  89. data/spec/opal/eventable_spec.rb +0 -75
  90. data/spec/opal/native/element_reference_spec.rb +0 -40
  91. data/spec/opal/native/equal_spec.rb +0 -17
  92. data/spec/opal/native/fixtures/classes.rb +0 -27
  93. data/spec/opal/native/global_spec.rb +0 -12
  94. data/spec/opal/native/initialize_spec.rb +0 -8
  95. data/spec/opal/native/method_missing_spec.rb +0 -53
  96. data/spec/opal/native/to_native_spec.rb +0 -8
  97. data/spec/rubyspec/core/string/demodulize_spec.rb +0 -10
  98. data/spec/rubyspec/core/string/underscore_spec.rb +0 -17
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## 0.3.44 2013-05-31
2
+
3
+ * Cleanup runtime, and remove various flags and functions from opal
4
+ objects and classes (moving them to runtime methods).
5
+
6
+ * Remove some activesupport methods into external lib.
7
+
8
+ * Add/fix lots of String methods, with specs.
9
+
10
+ * Add more methods to MatchData class.
11
+
12
+ * Implement $' and $` variables.
13
+
14
+ * Opal can now call methods on all native objects, via method missing
15
+ dispatcher.
16
+
17
+ * Add Opal::Environment as custom sprockets subclass which adds all
18
+ opal load paths automatically.
19
+
1
20
  ## 0.3.43 2013-05-02
2
21
 
3
22
  * Stop inlining respond_to? inside the parser. This now fully respects
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Opal
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/opal/opal.png?branch=master)](http://travis-ci.org/opal/opal)
4
+ [![Gem Version](https://badge.fury.io/rb/opal.png)](http://badge.fury.io/rb/opal)
4
5
 
5
6
  Opal is a ruby to javascript source-to-source compiler. It also has an
6
7
  implementation of the ruby corelib.
data/Rakefile CHANGED
@@ -47,21 +47,21 @@ namespace :spec do
47
47
  #Example:
48
48
  #spec:core => spec/core/
49
49
  #spec:core:array:allocae => spec/core/array/allocate_spec.rb
50
- def path(dirs)
50
+ def path(dirs)
51
51
  path = "#{Dir.pwd}"
52
52
  dirs.each do |dir|
53
- base = path + "/#{dir}"
53
+ base = path + "/#{dir}"
54
54
  if Dir.exists?(base)
55
55
  path = base
56
56
  else
57
57
  path = Dir.glob("#{base}_spec.rb")
58
- end
58
+ end
59
59
  end
60
60
  path = [path].flatten
61
61
  raise "File or Dir with task #{t.name} not found." if path.empty?
62
62
  path
63
63
  end
64
-
64
+
65
65
  RunSpec.new(path(t.name.split(":")))
66
66
  end
67
67
  end
@@ -70,27 +70,31 @@ desc "Build opal.js and opal-parser.js to build/"
70
70
  task :dist do
71
71
  Opal::Processor.arity_check_enabled = false
72
72
 
73
- env = Sprockets::Environment.new
74
- Opal.paths.each { |p| env.append_path p }
73
+ env = Opal::Environment.new
75
74
 
76
75
  Dir.mkdir 'build' unless File.directory? 'build'
77
76
 
78
- File.open('build/opal.js', 'w+') { |f| f << env['opal'].to_s }
79
- File.open('build/opal-parser.js', 'w+') { |f| f << env['opal-parser'].to_s }
80
- end
77
+ %w[opal opal-parser].each do |lib|
78
+ puts "* building #{lib}..."
81
79
 
82
- desc "Check file sizes for opal.js runtime"
83
- task :sizes do
84
- Opal::Processor.arity_check_enabled = false
80
+ src = env[lib].to_s
81
+ min = uglify src
82
+ gzp = gzip min
85
83
 
86
- env = Sprockets::Environment.new
87
- Opal.paths.each { |p| env.append_path p }
84
+ File.open("build/#{lib}.js", 'w+') { |f| f << src }
85
+ File.open("build/#{lib}.min.js", 'w+') { |f| f << min } if min
86
+ File.open("build/#{lib}.min.js.gz", 'w+') { |f| f << gzp } if gzp
88
87
 
89
- src = env['opal'].to_s
90
- min = uglify src
91
- gzp = gzip min
88
+ print "done. (development: #{src.size}B"
89
+ print ", minified: #{min.size}B" if min
90
+ print ", gzipped: #{gzp.size}Bx" if gzp
91
+ puts ")."
92
+ puts
93
+ end
94
+ end
92
95
 
93
- puts "development: #{src.size}, minified: #{min.size}, gzipped: #{gzp.size}"
96
+ desc "Check file sizes for opal.js runtime"
97
+ task :sizes => :dist do
94
98
  end
95
99
 
96
100
  desc "Rebuild grammar.rb for opal parser"
@@ -100,11 +104,14 @@ end
100
104
 
101
105
  # Used for uglifying source to minify
102
106
  def uglify(str)
103
- IO.popen('uglifyjs -nc', 'r+') do |i|
107
+ IO.popen('uglifyjs --no-mangle --compress warnings=false', 'r+') do |i|
104
108
  i.puts str
105
109
  i.close_write
106
110
  return i.read
107
111
  end
112
+ rescue Errno::ENOENT
113
+ $stderr.puts '"uglifyjs" command not found (install with: "npm install -g uglify-js")'
114
+ nil
108
115
  end
109
116
 
110
117
  # Gzip code to check file size
@@ -114,4 +121,7 @@ def gzip(str)
114
121
  i.close_write
115
122
  return i.read
116
123
  end
124
+ rescue Errno::ENOENT
125
+ $stderr.puts '"gzip" command not found, it is required to produce the .gz version'
126
+ nil
117
127
  end
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'opal', :path => '../..'
@@ -0,0 +1,17 @@
1
+ # opal native example
2
+
3
+ This example shows how native objects and functions can be called
4
+ directly from ruby code.
5
+
6
+ ## Usage
7
+
8
+ First, change into this directory and get required gems:
9
+
10
+ $ bundle install
11
+
12
+ Run the rack server:
13
+
14
+ $ bundle exec rackup
15
+
16
+ Now just visit `http://localhost:9292` in the browser, and view the
17
+ added elements on screen.
@@ -0,0 +1,38 @@
1
+ require 'opal'
2
+
3
+ $window.addEventListener 'DOMContentLoaded', proc {
4
+
5
+ css = <<-CSS
6
+ body {
7
+ font-family: 'Arial';
8
+ }
9
+ CSS
10
+
11
+ title = $document.createElement 'h1'
12
+ title.className = 'main-title'
13
+ title.innerHTML = 'Opal Native Example'
14
+
15
+ desc = $document.createElement 'p'
16
+ desc.innerHTML = "Hello world! From Opal."
17
+
18
+ target = $document.getElementById 'native-example'
19
+
20
+ unless target
21
+ raise "'native-example' doesn't exist?"
22
+ end
23
+
24
+ target.appendChild title
25
+ target.appendChild desc
26
+
27
+ styles = $document.createElement 'style'
28
+ styles.type = 'text/css'
29
+
30
+ if styles.respond_to? :styleSheet
31
+ styles.styleSheet.cssText = css
32
+ else
33
+ styles.appendChild $document.createTextNode css
34
+ end
35
+
36
+ $document.getElementsByTagName('head')[0].appendChild(styles)
37
+
38
+ }, false
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ run Opal::Server.new { |s|
5
+ s.append_path 'app'
6
+ s.debug = true
7
+ s.main = 'app'
8
+ }
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>opal native example</title>
6
+ <%= javascript_include_tag 'app' %>
7
+ </head>
8
+ <body>
9
+ <div id="native-example">
10
+ </div>
11
+ </body>
12
+ </html>
data/lib/opal/lexer.rb CHANGED
@@ -807,7 +807,11 @@ module Opal
807
807
 
808
808
  elsif scanner.check(/[0-9]/)
809
809
  @lex_state = :expr_end
810
- if scanner.scan(/[\d_]+\.[\d_]+\b|[\d_]+(\.[\d_]+)?[eE][-+]?[\d_]+\b/)
810
+ if scanner.scan(/0b?(0|1|_)+/)
811
+ return [:INTEGER, scanner.matched.to_i(2)]
812
+ elsif scanner.scan(/0o?([0-7]|_)+/)
813
+ return [:INTEGER, scanner.matched.to_i(8)]
814
+ elsif scanner.scan(/[\d_]+\.[\d_]+\b|[\d_]+(\.[\d_]+)?[eE][-+]?[\d_]+\b/)
811
815
  return [:FLOAT, scanner.matched.gsub(/_/, '').to_f]
812
816
  elsif scanner.scan(/[\d_]+\b/)
813
817
  return [:INTEGER, scanner.matched.gsub(/_/, '').to_i]
data/lib/opal/parser.rb CHANGED
@@ -22,7 +22,7 @@ module Opal
22
22
  break case catch continue debugger default delete do else finally for
23
23
  function if in instanceof new return switch this throw try typeof var let
24
24
  void while with class enum export extends import super true false native
25
- const
25
+ const static
26
26
  )
27
27
 
28
28
  # Statements which should not have ';' added to them.
@@ -52,6 +52,7 @@ module Opal
52
52
  @optimized_operators = (options[:optimized_operators] != false)
53
53
  @arity_check = options[:arity_check]
54
54
  @const_missing = (options[:const_missing] != false)
55
+ @dynamic_require_severity = (options[:dynamic_require_severity] || :error)
55
56
 
56
57
  @result = top(@sexp)
57
58
  end
@@ -68,6 +69,15 @@ module Opal
68
69
  raise SyntaxError, "#{msg} :#{@file}:#{@line}"
69
70
  end
70
71
 
72
+ # This is called when a parsing/processing warning occurs. This
73
+ # method simply appends the filename and curent line number onto
74
+ # the message and issues a warning.
75
+ #
76
+ # @param [String] msg warning message to raise
77
+ def warning(msg)
78
+ warn "#{msg} :#{@file}:#{@line}"
79
+ end
80
+
71
81
  # Instances of `Scope` can use this to determine the current
72
82
  # scope indent. The indent is used to keep generated code easily
73
83
  # readable.
@@ -643,7 +653,7 @@ module Opal
643
653
  code += "\n#@indent" + process(body, :stmt)
644
654
 
645
655
  if @scope.defines_defn
646
- @scope.add_temp "def = (#{current_self}._isObject ? #{current_self} : #{current_self}.prototype)"
656
+ @scope.add_temp "def = ((typeof(#{current_self}) === 'function') ? #{current_self}.prototype : #{current_self})"
647
657
  end
648
658
 
649
659
  code = "\n#@indent#{@scope.to_vars}\n#@indent#{code}"
@@ -780,7 +790,7 @@ module Opal
780
790
 
781
791
  def handle_require(sexp)
782
792
  str = handle_require_sexp sexp
783
- @requires << str
793
+ @requires << str unless str.nil?
784
794
  ""
785
795
  end
786
796
 
@@ -804,7 +814,13 @@ module Opal
804
814
  end
805
815
  end
806
816
 
807
- error "Cannot handle dynamic require"
817
+
818
+ case @dynamic_require_severity
819
+ when :error
820
+ error "Cannot handle dynamic require"
821
+ when :warning
822
+ warning "Cannot handle dynamic require"
823
+ end
808
824
  end
809
825
 
810
826
  def handle_expand_path(path, base = '')
@@ -931,7 +947,8 @@ module Opal
931
947
  @scope.add_temp "__scope = #{current_self}._scope"
932
948
  @scope.add_temp "def = #{current_self}.prototype"
933
949
 
934
- code = @scope.to_vars + process(body, :stmt)
950
+ body = process body, :stmt
951
+ code = @scope.to_vars + body
935
952
  end
936
953
 
937
954
  call = s(:call, recv, :singleton_class, s(:arglist))
@@ -1085,7 +1102,7 @@ module Opal
1085
1102
 
1086
1103
  if recvr
1087
1104
  if smethod
1088
- "#{ @scope.name }._defs('$#{mid}', #{defcode})"
1105
+ "__opal.defs(#{@scope.name}, '$#{mid}', #{defcode})"
1089
1106
  else
1090
1107
  "#{ recv }#{ jsid } = #{ defcode }"
1091
1108
  end
@@ -1424,8 +1441,12 @@ module Opal
1424
1441
  def process_const(sexp, level)
1425
1442
  cname = sexp.shift.to_s
1426
1443
 
1427
- with_temp do |t|
1428
- "((#{t} = __scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})"
1444
+ if @const_missing
1445
+ with_temp do |t|
1446
+ "((#{t} = __scope.#{cname}) == null ? __opal.cm(#{cname.inspect}) : #{t})"
1447
+ end
1448
+ else
1449
+ "__scope.#{cname}"
1429
1450
  end
1430
1451
  end
1431
1452
 
@@ -1760,9 +1781,14 @@ module Opal
1760
1781
  base = sexp[0]
1761
1782
  cname = sexp[1].to_s
1762
1783
 
1763
- with_temp do |t|
1784
+ if @const_missing
1785
+ with_temp do |t|
1786
+ base = process base, :expr
1787
+ "((#{t} = (#{base})._scope).#{cname} == null ? #{t}.cm(#{cname.inspect}) : #{t}.#{cname})"
1788
+ end
1789
+ else
1764
1790
  base = process base, :expr
1765
- "((#{t} = (#{base})._scope).#{cname} == null ? #{t}.cm(#{cname.inspect}) : #{t}.#{cname})"
1791
+ "(#{base})._scope.#{cname}"
1766
1792
  end
1767
1793
  end
1768
1794
 
@@ -4,10 +4,8 @@ module Opal
4
4
  # Proccess using Sprockets
5
5
  #
6
6
  # Opal.process('opal-jquery') # => String
7
- def self.process(asset)
8
- env = Sprockets::Environment.new
9
- Opal.paths.each { |p| env.append_path p }
10
- env[file].to_s
7
+ def self.process asset
8
+ Environment.new[asset].to_s
11
9
  end
12
10
 
13
11
  # The Processor class is used to make ruby files (with rb or opal extensions)
@@ -31,12 +29,14 @@ module Opal
31
29
  attr_accessor :optimized_operators_enabled
32
30
  attr_accessor :arity_check_enabled
33
31
  attr_accessor :const_missing_enabled
32
+ attr_accessor :dynamic_require_severity
34
33
  end
35
34
 
36
35
  self.method_missing_enabled = true
37
36
  self.optimized_operators_enabled = true
38
37
  self.arity_check_enabled = false
39
38
  self.const_missing_enabled = true
39
+ self.dynamic_require_severity = :error # :error, :warning or :ignore
40
40
 
41
41
  def initialize_engine
42
42
  require_template_library 'opal'
@@ -47,11 +47,12 @@ module Opal
47
47
 
48
48
  def evaluate(context, locals, &block)
49
49
  options = {
50
- :method_missing => self.class.method_missing_enabled,
51
- :optimized_operators => self.class.optimized_operators_enabled,
52
- :arity_check => self.class.arity_check_enabled,
53
- :const_missing => self.class.const_missing_enabled,
54
- :file => context.logical_path
50
+ :method_missing => self.class.method_missing_enabled,
51
+ :optimized_operators => self.class.optimized_operators_enabled,
52
+ :arity_check => self.class.arity_check_enabled,
53
+ :const_missing => self.class.const_missing_enabled,
54
+ :dynamic_require_severity => self.class.dynamic_require_severity,
55
+ :file => context.logical_path
55
56
  }
56
57
 
57
58
  parser = Opal::Parser.new
data/lib/opal/server.rb CHANGED
@@ -1,22 +1,27 @@
1
1
  require 'erb'
2
2
 
3
3
  module Opal
4
+ class Environment < ::Sprockets::Environment
5
+ def initialize *args
6
+ super
7
+ Opal.paths.each { |p| append_path p }
8
+ end
9
+ end
10
+
4
11
  class Server
5
12
 
6
13
  attr_accessor :debug, :index_path, :main, :public_dir, :sprockets
7
14
 
8
- def initialize(debug = true)
9
- @sprockets = ::Sprockets::Environment.new
10
- Opal.paths.each { |p| @sprockets.append_path p }
11
-
15
+ def initialize debug = true
12
16
  @public_dir = '.'
13
- @debug = debug
17
+ @sprockets = Environment.new
18
+ @debug = debug
14
19
 
15
20
  yield self if block_given?
16
21
  create_app
17
22
  end
18
23
 
19
- def append_path(path)
24
+ def append_path path
20
25
  @sprockets.append_path path
21
26
  end
22
27
 
@@ -50,10 +55,15 @@ module Opal
50
55
  end
51
56
  end
52
57
 
58
+ # Returns the html content for the root path. Supports ERB
53
59
  def html
54
60
  source = if @index_path
55
61
  raise "index does not exist: #{@index_path}" unless File.exist?(@index_path)
56
62
  File.read @index_path
63
+ elsif File.exist? 'index.html'
64
+ File.read 'index.html'
65
+ elsif File.exist? 'index.html.erb'
66
+ File.read 'index.html.erb'
57
67
  else
58
68
  SOURCE
59
69
  end
@@ -61,7 +71,7 @@ module Opal
61
71
  ::ERB.new(source).result binding
62
72
  end
63
73
 
64
- def javascript_include_tag(source)
74
+ def javascript_include_tag source
65
75
  if @server.debug
66
76
  assets = @server.sprockets[source].to_a
67
77