opal 0.7.0.beta3 → 0.7.0.rc1

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.
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}))`