opal 0.7.0.beta3 → 0.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +4 -0
  3. data/.travis.yml +7 -3
  4. data/.yardopts +6 -0
  5. data/CHANGELOG.md +28 -0
  6. data/Gemfile +1 -1
  7. data/README.md +3 -12
  8. data/Rakefile +4 -150
  9. data/bin/opal-mspec +1 -1
  10. data/docs/compiler_directives.md +127 -0
  11. data/examples/rack/.gitignore +1 -0
  12. data/examples/rack/app/user.rb +1 -0
  13. data/lib/mspec/opal/special_calls.rb +15 -2
  14. data/lib/opal/builder.rb +15 -8
  15. data/lib/opal/compiler.rb +75 -4
  16. data/lib/opal/erb.rb +22 -2
  17. data/lib/opal/fragment.rb +17 -5
  18. data/lib/opal/nodes/def.rb +174 -53
  19. data/lib/opal/nodes/if.rb +14 -0
  20. data/lib/opal/nodes/module.rb +0 -1
  21. data/lib/opal/nodes/rescue.rb +10 -2
  22. data/lib/opal/nodes/scope.rb +0 -17
  23. data/lib/opal/parser.rb +83 -19
  24. data/lib/opal/parser/grammar.rb +2511 -2414
  25. data/lib/opal/parser/grammar.y +71 -9
  26. data/lib/opal/parser/lexer.rb +44 -12
  27. data/lib/opal/parser/parser_scope.rb +3 -0
  28. data/lib/opal/parser/sexp.rb +7 -1
  29. data/lib/opal/paths.rb +5 -5
  30. data/lib/opal/sprockets/environment.rb +2 -10
  31. data/lib/opal/sprockets/path_reader.rb +1 -1
  32. data/lib/opal/sprockets/processor.rb +1 -0
  33. data/lib/opal/sprockets/server.rb +2 -0
  34. data/lib/opal/util.rb +7 -2
  35. data/lib/opal/version.rb +1 -1
  36. data/opal.gemspec +1 -0
  37. data/opal/README.md +1 -1
  38. data/opal/corelib/dir.rb +1 -1
  39. data/opal/corelib/enumerable.rb +3 -1
  40. data/opal/corelib/error.rb +3 -0
  41. data/opal/corelib/file.rb +2 -0
  42. data/opal/corelib/hash.rb +3 -0
  43. data/opal/corelib/io.rb +15 -1
  44. data/opal/corelib/kernel.rb +8 -0
  45. data/opal/corelib/module.rb +42 -17
  46. data/opal/corelib/runtime.js +223 -49
  47. data/opal/corelib/string.rb +1 -1
  48. data/opal/corelib/struct.rb +1 -7
  49. data/spec/README.md +8 -0
  50. data/spec/filters/bugs/language.rb +1 -0
  51. data/spec/filters/bugs/module.rb +4 -0
  52. data/spec/filters/unsupported/frozen.rb +2 -0
  53. data/spec/lib/compiler/pre_processed_conditionals_spec.rb +87 -0
  54. data/spec/lib/compiler_spec.rb +1 -67
  55. data/spec/lib/fixtures/file_with_directives.js +2 -0
  56. data/spec/lib/fixtures/required_file.js +1 -0
  57. data/spec/lib/parser/def_spec.rb +29 -16
  58. data/spec/lib/parser/variables_spec.rb +5 -5
  59. data/spec/lib/sprockets/path_reader_spec.rb +24 -8
  60. data/spec/lib/sprockets/server_spec.rb +10 -3
  61. data/spec/opal/core/date_spec.rb +14 -0
  62. data/spec/opal/core/language/versions/def_2_0_spec.rb +62 -0
  63. data/spec/opal/core/language_spec.rb +23 -0
  64. data/spec/opal/core/runtime/donate_spec.rb +53 -0
  65. data/spec/opal/stdlib/native/native_alias_spec.rb +19 -0
  66. data/spec/opal/stdlib/native/native_class_spec.rb +18 -0
  67. data/spec/opal/stdlib/native/native_module_spec.rb +13 -0
  68. data/spec/rubyspecs +2 -0
  69. data/stdlib/buffer.rb +1 -0
  70. data/stdlib/date.rb +18 -0
  71. data/stdlib/encoding.rb +3 -2
  72. data/stdlib/minitest.rb +780 -0
  73. data/stdlib/minitest/assertions.rb +662 -0
  74. data/stdlib/minitest/autorun.rb +12 -0
  75. data/stdlib/minitest/benchmark.rb +426 -0
  76. data/stdlib/minitest/expectations.rb +281 -0
  77. data/stdlib/minitest/hell.rb +11 -0
  78. data/stdlib/minitest/mock.rb +220 -0
  79. data/stdlib/minitest/parallel.rb +65 -0
  80. data/stdlib/minitest/pride.rb +4 -0
  81. data/stdlib/minitest/pride_plugin.rb +142 -0
  82. data/stdlib/minitest/spec.rb +310 -0
  83. data/stdlib/minitest/test.rb +293 -0
  84. data/stdlib/minitest/unit.rb +45 -0
  85. data/stdlib/native.rb +12 -3
  86. data/stdlib/nodejs/process.rb +16 -2
  87. data/stdlib/promise.rb +99 -0
  88. data/stdlib/test/unit.rb +10 -0
  89. data/stdlib/thread.rb +4 -0
  90. data/tasks/building.rake +58 -0
  91. data/tasks/documentation.rake +38 -0
  92. data/tasks/documenting.rake +37 -0
  93. data/tasks/testing.rake +102 -0
  94. metadata +57 -2
@@ -15,7 +15,7 @@ token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS
15
15
  tLCURLY tRCURLY tBACK_REF2 tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG
16
16
  tWORDS_BEG tAWORDS_BEG tSTRING_DBEG tSTRING_DVAR tSTRING_END tSTRING
17
17
  tSYMBOL tNL tEH tCOLON tCOMMA tSPACE tSEMI tLAMBDA tLAMBEG
18
- tLBRACK2 tLBRACK
18
+ tLBRACK2 tLBRACK tDSTAR
19
19
 
20
20
  prechigh
21
21
  right tBANG tTILDE tUPLUS
@@ -1458,35 +1458,97 @@ xstring_contents: none
1458
1458
  result = val[0]
1459
1459
  }
1460
1460
 
1461
- f_args: f_arg tCOMMA f_optarg tCOMMA f_rest_arg opt_f_block_arg
1461
+ kwrest_mark: tPOW
1462
+ | tDSTAR
1463
+
1464
+ f_kwrest: kwrest_mark tIDENTIFIER
1465
+ {
1466
+ result = new_kwrestarg(val[1])
1467
+ }
1468
+ | kwrest_mark
1469
+ {
1470
+ result = new_kwrestarg()
1471
+ }
1472
+
1473
+ f_label: tLABEL
1474
+ {
1475
+ result = new_sym(val[0])
1476
+ }
1477
+
1478
+ f_kw: f_label arg_value
1479
+ {
1480
+ result = new_kwoptarg(val[0], val[1])
1481
+ }
1482
+ | f_label
1483
+ {
1484
+ result = new_kwarg(val[0])
1485
+ }
1486
+
1487
+ f_kwarg: f_kw
1488
+ {
1489
+ result = [val[0]]
1490
+ }
1491
+ | f_kwarg tCOMMA f_kw
1492
+ {
1493
+ result = val[0]
1494
+ result << val[2]
1495
+ }
1496
+
1497
+ args_tail: f_kwarg tCOMMA f_kwrest opt_f_block_arg
1498
+ {
1499
+ result = new_args_tail(val[0], val[2], val[3])
1500
+ }
1501
+ | f_kwarg opt_f_block_arg
1502
+ {
1503
+ result = new_args_tail(val[0], nil, val[1])
1504
+ }
1505
+ | f_kwrest opt_f_block_arg
1506
+ {
1507
+ result = new_args_tail(nil, val[0], val[1])
1508
+ }
1509
+ | f_block_arg
1510
+ {
1511
+ result = new_args_tail(nil, nil, val[0])
1512
+ }
1513
+
1514
+ opt_args_tail: tCOMMA args_tail
1515
+ {
1516
+ result = val[1]
1517
+ }
1518
+ | # none
1519
+ {
1520
+ result = new_args_tail(nil, nil, nil)
1521
+ }
1522
+
1523
+ f_args: f_arg tCOMMA f_optarg tCOMMA f_rest_arg opt_args_tail
1462
1524
  {
1463
1525
  result = new_args(val[0], val[2], val[4], val[5])
1464
1526
  }
1465
- | f_arg tCOMMA f_optarg opt_f_block_arg
1527
+ | f_arg tCOMMA f_optarg opt_args_tail
1466
1528
  {
1467
1529
  result = new_args(val[0], val[2], nil, val[3])
1468
1530
  }
1469
- | f_arg tCOMMA f_rest_arg opt_f_block_arg
1531
+ | f_arg tCOMMA f_rest_arg opt_args_tail
1470
1532
  {
1471
1533
  result = new_args(val[0], nil, val[2], val[3])
1472
1534
  }
1473
- | f_arg opt_f_block_arg
1535
+ | f_arg opt_args_tail
1474
1536
  {
1475
1537
  result = new_args(val[0], nil, nil, val[1])
1476
1538
  }
1477
- | f_optarg tCOMMA f_rest_arg opt_f_block_arg
1539
+ | f_optarg tCOMMA f_rest_arg opt_args_tail
1478
1540
  {
1479
1541
  result = new_args(nil, val[0], val[2], val[3])
1480
1542
  }
1481
- | f_optarg opt_f_block_arg
1543
+ | f_optarg opt_args_tail
1482
1544
  {
1483
1545
  result = new_args(nil, val[0], nil, val[1])
1484
1546
  }
1485
- | f_rest_arg opt_f_block_arg
1547
+ | f_rest_arg opt_args_tail
1486
1548
  {
1487
1549
  result = new_args(nil, nil, val[0], val[1])
1488
1550
  }
1489
- | f_block_arg
1551
+ | args_tail
1490
1552
  {
1491
1553
  result = new_args(nil, nil, nil, val[0])
1492
1554
  }
@@ -2,6 +2,23 @@ require 'strscan'
2
2
  require 'opal/parser/keywords'
3
3
 
4
4
  module Opal
5
+ # {Opal::Lexer} is used by {Opal::Parser} to step through ruby code, and
6
+ # returning tokens representing each chunk of ruby code.
7
+ #
8
+ # Tokens are in the form:
9
+ #
10
+ # [token, [value, location]]
11
+ #
12
+ # where `location` is in the form `[line_number, column_number]`. The location
13
+ # data can be used to produce source maps in the compiler. Tokens are
14
+ # generally ruby symbols, and the value will always be a string value.
15
+ #
16
+ # The main method used by the parser is {#next_token}, which is called
17
+ # repeatedly until a token of value `false` is returned, which indicated the
18
+ # EOF has been reached.
19
+ #
20
+ # Generally this class is only used by {Opal::Parser} directly.
21
+ #
5
22
  class Lexer
6
23
 
7
24
  STR_FUNC_ESCAPE = 0x01
@@ -31,6 +48,13 @@ module Opal
31
48
  attr_accessor :yylval
32
49
  attr_accessor :parser
33
50
 
51
+ # Create a new instance using the given ruby code and filename for
52
+ # reference.
53
+ #
54
+ # Opal::Lexer.new("ruby code", "my_file.rb")
55
+ #
56
+ # @param source [String] ruby code to lex
57
+ # @param file [String] filename of given ruby code
34
58
  def initialize(source, file)
35
59
  @lex_state = :expr_beg
36
60
  @cond = 0
@@ -48,6 +72,25 @@ module Opal
48
72
  @start_of_lambda = nil
49
73
  end
50
74
 
75
+ # Returns next token from source input stream.
76
+ #
77
+ # Token in form:
78
+ #
79
+ # [token, [value, [source_line, source_column]]]
80
+ #
81
+ # @return [Array]
82
+ def next_token
83
+ token = self.yylex
84
+ value = self.yylval
85
+ location = [@tok_line, @tok_column]
86
+
87
+ # once location is stored, ensure next token starts in correct place
88
+ @tok_column = @column
89
+ @tok_line = @line
90
+
91
+ [token, [value, location]]
92
+ end
93
+
51
94
  def has_local?(local)
52
95
  parser.scope.has_local?(local.to_sym)
53
96
  end
@@ -151,18 +194,6 @@ module Opal
151
194
  @line = @tok_line = line
152
195
  end
153
196
 
154
- def next_token
155
- token = self.yylex
156
- value = self.yylval
157
- location = [@tok_line, @tok_column]
158
-
159
- # once location is stored, ensure next token starts in correct place
160
- @tok_column = @column
161
- @tok_line = @line
162
-
163
- [token, [value, location]]
164
- end
165
-
166
197
  def new_strterm(func, term, paren)
167
198
  { :type => :string, :func => func, :term => term, :paren => paren }
168
199
  end
@@ -600,6 +631,7 @@ module Opal
600
631
  return matched =~ /^[A-Z]/ ? :tCONSTANT : :tIDENTIFIER
601
632
  end
602
633
 
634
+ # Does the heavy lifting for `next_token`.
603
635
  def yylex
604
636
  @yylval = ''
605
637
  @space_seen = false
@@ -6,6 +6,9 @@ module Opal
6
6
  attr_reader :locals
7
7
  attr_accessor :parent
8
8
 
9
+ # Create new parse scope. Valid types are :block, :class, :module, :def.
10
+ #
11
+ # @param type [Symbol] scope type
9
12
  def initialize(type)
10
13
  @block = type == :block
11
14
  @locals = []
@@ -1,4 +1,11 @@
1
1
  module Opal
2
+ # [Opal::Sexp] is used to build up the syntax tree inside [Opal::Parser]. The
3
+ # compiler then steps through the sexp trees to generate the javascript code.
4
+ #
5
+ # For example, an array of integers `[1, 2]` might be represented by:
6
+ #
7
+ # s(:array, s(:int, 1), s(:int, 2))
8
+ #
2
9
  class Sexp
3
10
 
4
11
  attr_reader :array
@@ -72,4 +79,3 @@ module Opal
72
79
  alias to_s inspect
73
80
  end
74
81
  end
75
-
data/lib/opal/paths.rb CHANGED
@@ -19,19 +19,19 @@ module Opal
19
19
  paths << path
20
20
  end
21
21
 
22
- def self.use_gem(gem_name, include_dependecies = true)
23
- require_paths_for_gem(gem_name, include_dependecies).each do |path|
22
+ def self.use_gem(gem_name, include_dependencies = true)
23
+ require_paths_for_gem(gem_name, include_dependencies).each do |path|
24
24
  append_path path
25
25
  end
26
26
  end
27
27
 
28
- def self.require_paths_for_gem(gem_name, include_dependecies)
28
+ def self.require_paths_for_gem(gem_name, include_dependencies)
29
29
  paths = []
30
30
  spec = Gem::Specification.find_by_name(gem_name)
31
31
 
32
32
  spec.runtime_dependencies.each do |dependency|
33
- paths += require_paths_for_gem(dependency.name, include_dependecies)
34
- end if include_dependecies
33
+ paths += require_paths_for_gem(dependency.name, include_dependencies)
34
+ end if include_dependencies
35
35
 
36
36
  gem_dir = spec.gem_dir
37
37
  spec.require_paths.map do |path|
@@ -3,20 +3,12 @@ require 'opal/sprockets/processor'
3
3
  require 'opal/sprockets/erb'
4
4
 
5
5
  module Opal
6
- # Proccess using Sprockets
7
- #
8
- # Opal.process('opal-jquery') # => String
6
+ # @deprecated
9
7
  def self.process asset
10
8
  Environment.new[asset].to_s
11
9
  end
12
10
 
13
- # Environment is a subclass of Sprockets::Environment which already has our opal
14
- # load paths loaded. This makes it easy for stand-alone rack apps, or test runners
15
- # that have opal load paths ready to use. You can also add an existing gem's lib
16
- # directory to our load path to use real gems inside your opal environment.
17
- #
18
- # If you are running rails, then you just need opal-rails instead, which will
19
- # do this for you.
11
+ # @deprecated
20
12
  class Environment < ::Sprockets::Environment
21
13
  def initialize *args
22
14
  warn "WARNING: Opal::Sprockets::Environment is deprecated. "\
@@ -10,7 +10,7 @@ module Opal
10
10
  def read path
11
11
  if path.end_with? '.js'
12
12
  context.depend_on_asset(path)
13
- env[path].to_s
13
+ env[path, bundle: true].to_s
14
14
  else
15
15
  context.depend_on(path)
16
16
  File.read(expand(path))
@@ -60,6 +60,7 @@ module Opal
60
60
  self.dynamic_require_severity = :error # :error, :warning or :ignore
61
61
  self.source_map_enabled = true
62
62
  self.irb_enabled = false
63
+ self.inline_operators_enabled = false
63
64
 
64
65
  self.source_map_register = $OPAL_SOURCE_MAPS
65
66
 
@@ -36,6 +36,8 @@ module Opal
36
36
 
37
37
  # "logical_name" of a BundledAsset keeps the .js extension
38
38
  source = register[asset.logical_path.sub(/\.js$/, '')]
39
+ return not_found(asset) if source.nil?
40
+
39
41
  map = JSON.parse(source)
40
42
  map['sources'] = map['sources'].map {|s| "#{prefix}/#{s}"}
41
43
  source = map.to_json
data/lib/opal/util.rb CHANGED
@@ -2,13 +2,18 @@ module Opal
2
2
  module Util
3
3
  extend self
4
4
 
5
- # Used for uglifying source to minify
5
+ # Used for uglifying source to minify.
6
+ #
7
+ # Opal::Util.uglify("javascript contents")
8
+ #
9
+ # @param str [String] string to minify
10
+ # @return [String]
6
11
  def uglify(str)
7
12
  uglifyjs = DigestSourceCommand.new(:uglifyjs, nil, ' (install with: "npm install -g uglify-js")')
8
13
  uglifyjs.digest(str)
9
14
  end
10
15
 
11
- # Gzip code to check file size
16
+ # Gzip code to check file size.
12
17
  def gzip(str)
13
18
  gzip = DigestSourceCommand.new(:gzip, '-f', ', it is required to produce the .gz version')
14
19
  gzip.digest(str)
data/lib/opal/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Opal
2
- VERSION = '0.7.0.beta3'
2
+ VERSION = '0.7.0.rc1'
3
3
  end
data/opal.gemspec CHANGED
@@ -33,4 +33,5 @@ Gem::Specification.new do |s|
33
33
  s.add_development_dependency 'bundler', '~> 1.5'
34
34
  s.add_development_dependency 'yard', '~> 0.8.7'
35
35
  s.add_development_dependency 'rack-test'
36
+ s.add_development_dependency 'opal-minitest'
36
37
  end
data/opal/README.md CHANGED
@@ -3,4 +3,4 @@
3
3
  This is the Opal corelib implementation API documentation.
4
4
  The whole corelib is loaded upon `require 'opal'`.
5
5
 
6
- The `runtime.js` documentation is [availble here](runtime.js.html)
6
+ The `runtime.js` documentation is [available here](runtime.js.html)
data/opal/corelib/dir.rb CHANGED
@@ -9,7 +9,7 @@ class Dir
9
9
  end
10
10
 
11
11
  def pwd
12
- `Opal.current_dir` || '.'
12
+ `Opal.current_dir || '.'`
13
13
  end
14
14
  alias getwd pwd
15
15
 
@@ -1079,7 +1079,9 @@ module Enumerable
1079
1079
  end
1080
1080
 
1081
1081
  def sort(&block)
1082
- raise NotImplementedError
1082
+ ary = to_a
1083
+ block = -> a,b {a <=> b} unless block_given?
1084
+ return `ary.sort(block)`
1083
1085
  end
1084
1086
 
1085
1087
  def sort_by(&block)
@@ -48,6 +48,9 @@ class LoadError < ScriptError; end
48
48
  class NotImplementedError < ScriptError; end
49
49
 
50
50
  class SystemExit < Exception; end
51
+ class NoMemoryError < Exception; end
52
+ class SignalException < Exception; end
53
+ class Interrupt < Exception; end
51
54
 
52
55
  class StandardError < Exception; end
53
56
  class NameError < StandardError; end
data/opal/corelib/file.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  class File < IO
2
2
  Separator = SEPARATOR = '/'
3
+ ALT_SEPARATOR = nil
4
+ PATH_SEPARATOR = ':'
3
5
 
4
6
  class << self
5
7
  def expand_path(path, basedir = nil)
data/opal/corelib/hash.rb CHANGED
@@ -3,6 +3,9 @@ require 'corelib/enumerable'
3
3
  class Hash
4
4
  include Enumerable
5
5
 
6
+ # Mark all hash instances as valid hashes (used to check keyword args, etc)
7
+ `def.$$is_hash = true`
8
+
6
9
  def self.[](*objs)
7
10
  `Opal.hash.apply(null, objs)`
8
11
  end
data/opal/corelib/io.rb CHANGED
@@ -3,6 +3,14 @@ class IO
3
3
  SEEK_CUR = 1
4
4
  SEEK_END = 2
5
5
 
6
+ def tty?
7
+ @tty
8
+ end
9
+
10
+ def closed?
11
+ @closed
12
+ end
13
+
6
14
  attr_accessor :write_proc
7
15
 
8
16
  def write(string)
@@ -10,6 +18,8 @@ class IO
10
18
  string.size
11
19
  end
12
20
 
21
+ attr_accessor :sync
22
+
13
23
  module Writable
14
24
  def <<(string)
15
25
  write(string)
@@ -23,7 +33,11 @@ class IO
23
33
 
24
34
  def puts(*args)
25
35
  newline = $/
26
- write args.map { |arg| String(arg).chomp }.concat([nil]).join(newline)
36
+ if args.empty?
37
+ write $/
38
+ else
39
+ write args.map { |arg| String(arg).chomp }.concat([nil]).join(newline)
40
+ end
27
41
  nil
28
42
  end
29
43
  end
@@ -71,6 +71,11 @@ module Kernel
71
71
  }
72
72
  end
73
73
 
74
+ def at_exit(&block)
75
+ $__at_exit__ ||= []
76
+ $__at_exit__ << block
77
+ end
78
+
74
79
  # Opal does not support #caller, but we stub it as an empty array to not
75
80
  # break dependant libs
76
81
  def caller
@@ -405,6 +410,7 @@ module Kernel
405
410
  end
406
411
 
407
412
  def load(file)
413
+ file = Opal.coerce_to!(file, String, :to_str)
408
414
  `Opal.load(Opal.normalize_loadable_path(#{file}))`
409
415
  end
410
416
 
@@ -521,10 +527,12 @@ module Kernel
521
527
  end
522
528
 
523
529
  def require(file)
530
+ file = Opal.coerce_to!(file, String, :to_str)
524
531
  `Opal.require(Opal.normalize_loadable_path(#{file}))`
525
532
  end
526
533
 
527
534
  def require_relative(file)
535
+ Opal.try_convert!(file, String, :to_str)
528
536
  file = File.expand_path File.join(`Opal.current_file`, '..', file)
529
537
 
530
538
  `Opal.require(Opal.normalize_loadable_path(#{file}))`