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
@@ -71,7 +71,7 @@ class String
71
71
  end
72
72
 
73
73
  def <<(other)
74
- raise NotImplementedError, 'Mutable String methods are not supported in Opal.'
74
+ raise NotImplementedError, '#<< not supported. Mutable String methods are not supported in Opal.'
75
75
  end
76
76
 
77
77
  def ==(other)
@@ -22,13 +22,7 @@ class Struct
22
22
 
23
23
  members << name
24
24
 
25
- define_method name do
26
- instance_variable_get "@#{name}"
27
- end
28
-
29
- define_method "#{name}=" do |value|
30
- instance_variable_set "@#{name}", value
31
- end
25
+ attr_accessor name
32
26
  end
33
27
 
34
28
  def self.members
data/spec/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # Opal specs overview
2
+
3
+ * **rubyspecs** (file) a whitelist of RubySpec files to be ran
4
+ * **corelib** RubySpec examples (submodule)
5
+ * **stdlib** `rubysl-*` examples (submodules)
6
+ * **filters** The list of MSpec/RubySpec examples that are either bugs or unsupported
7
+ * **opal** opal additions/special behaviour in the runtime/corelib
8
+ * **lib** specs for opal lib (parser, lexer, grammar, compiler etc)
@@ -147,6 +147,7 @@ opal_filter "language" do
147
147
  fails "A singleton method definition can be declared for a global variable"
148
148
  fails "A singleton method definition can be declared for an instance variable"
149
149
  fails "A singleton method definition can be declared for a local variable"
150
+ fails "An instance method with keyword arguments when there is a single keyword argument raises an argument error when an unknown keyword argument is provided"
150
151
 
151
152
  fails "The defined? keyword for a scoped constant returns nil when an undefined constant is scoped to a defined constant"
152
153
  fails "The defined? keyword for a top-level scoped constant returns nil when an undefined constant is scoped to a defined constant"
@@ -12,6 +12,9 @@ opal_filter "Module" do
12
12
  fails "Module#const_defined? should not search parent scopes of classes and modules if inherit is false"
13
13
  fails "Module#const_get should not search parent scopes of classes and modules if inherit is false"
14
14
 
15
+ fails "Module#class_variable_set sets the value of a class variable with the given name defined in an included module"
16
+ fails "Module#class_variable_get returns the value of a class variable with the given name defined in an included module"
17
+
15
18
  fails "Module#module_function as a toggle (no arguments) in a Module body functions normally if both toggle and definitions inside a eval"
16
19
  fails "Module#module_function as a toggle (no arguments) in a Module body does not affect definitions when inside an eval even if the definitions are outside of it"
17
20
 
@@ -24,4 +27,5 @@ opal_filter "Module" do
24
27
  fails "Module#module_function with specific method names can make accessible private methods"
25
28
  fails "Module#module_function as a toggle (no arguments) in a Module body does not affect module_evaled method definitions also if outside the eval itself"
26
29
  fails "Module#module_function as a toggle (no arguments) in a Module body has no effect if inside a module_eval if the definitions are outside of it"
30
+ fails "Module#module_function with specific method names creates an independent copy of the method, not a redirect"
27
31
  end
@@ -87,4 +87,6 @@ opal_filter "Object#frozen" do
87
87
  fails "Hash#update raises a RuntimeError on a frozen instance that is modified"
88
88
  fails "Hash#rehash raises a RuntimeError if called on a frozen instance"
89
89
  fails "Hash#[]= duplicates and freezes string keys"
90
+
91
+ fails "Module#class_variable_set raises a RuntimeError when self is frozen"
90
92
  end
@@ -0,0 +1,87 @@
1
+ require 'lib/spec_helper'
2
+
3
+ describe Opal::Compiler do
4
+ def expect_compiled(*args)
5
+ expect(Opal::Compiler.new(*args).compile)
6
+ end
7
+
8
+ describe "pre-processed if conditions" do
9
+ it "compiles if blocks using RUBY_ENGINE/RUBY_PLATFORM == opal" do
10
+ expect_compiled(<<-RUBY).to include("should_compile_fine")
11
+ if RUBY_ENGINE == 'opal'
12
+ :should_compile_fine
13
+ end
14
+ RUBY
15
+
16
+ expect_compiled(<<-RUBY).to include("so_should_this")
17
+ if RUBY_PLATFORM == 'opal'
18
+ :so_should_this
19
+ end
20
+ RUBY
21
+ end
22
+
23
+ it "does not compile if blocks using RUBY_ENGINE/RUBY_PLATFORM != opal" do
24
+ expect_compiled(<<-RUBY).to_not include('should_not_compile')
25
+ if RUBY_ENGINE != 'opal'
26
+ :should_not_compile
27
+ end
28
+ RUBY
29
+
30
+ expect_compiled(<<-RUBY).to_not include('should_not_compile')
31
+ if RUBY_PLATFORM != 'opal'
32
+ :should_not_compile
33
+ end
34
+ RUBY
35
+ end
36
+
37
+ it "skips elsif/else parts for CONST == opal" do
38
+ expect_compiled(<<-RUBY).to_not include("should_be_skipped")
39
+ if RUBY_PLATFORM == "opal"
40
+ :ok
41
+ else
42
+ :should_be_skipped
43
+ end
44
+ RUBY
45
+
46
+ result = expect_compiled(<<-RUBY)
47
+ if RUBY_ENGINE == 'opal'
48
+ :this_compiles
49
+ elsif false
50
+ :this_does_not_compile
51
+ else
52
+ :this_neither
53
+ end
54
+ RUBY
55
+
56
+ result.to_not include("this_does_not_compile", "this_neither")
57
+ end
58
+
59
+ it "generates if-code as normal without check" do
60
+ expect_compiled(<<-RUBY).to include("should_compile", "and_this")
61
+ if some_conditional
62
+ :should_compile
63
+ else
64
+ :and_this
65
+ end
66
+ RUBY
67
+ end
68
+ end
69
+
70
+ describe "pre-processed unless conditionals" do
71
+ it "skips over if using RUBY_ENGINE/RUBY_PLATFORM == 'opal'" do
72
+ expect_compiled(<<-RUBY).to_not include("should_not_compile")
73
+ unless RUBY_ENGINE == 'opal'
74
+ :should_not_compile
75
+ end
76
+ RUBY
77
+ end
78
+
79
+ it "generates unless code as normal if no check" do
80
+ expect_compiled(<<-RUBY).to include("this_should_compile")
81
+ unless this_is_true
82
+ :this_should_compile
83
+ end
84
+ RUBY
85
+ end
86
+ end
87
+ end
@@ -83,73 +83,7 @@ describe Opal::Compiler do
83
83
  end
84
84
  end
85
85
 
86
- describe "pre-processed if conditions" do
87
- it "compiles if blocks using RUBY_ENGINE/RUBY_PLATFORM == opal" do
88
- expect_compiled(<<-RUBY).to include("should_compile_fine")
89
- if RUBY_ENGINE == 'opal'
90
- :should_compile_fine
91
- end
92
- RUBY
93
-
94
- expect_compiled(<<-RUBY).to include("so_should_this")
95
- if RUBY_PLATFORM == 'opal'
96
- :so_should_this
97
- end
98
- RUBY
99
- end
100
-
101
- it "skips elsif/else parts" do
102
- expect_compiled(<<-RUBY).to_not include("should_be_skipped")
103
- if RUBY_PLATFORM == "opal"
104
- :ok
105
- else
106
- :should_be_skipped
107
- end
108
- RUBY
109
-
110
- result = expect_compiled(<<-RUBY)
111
- if RUBY_ENGINE == 'opal'
112
- :this_compiles
113
- elsif false
114
- :this_does_not_compile
115
- else
116
- :this_neither
117
- end
118
- RUBY
119
-
120
- result.to_not include("this_does_not_compile", "this_neither")
121
- end
122
-
123
- it "generates if-code as normal without check" do
124
- expect_compiled(<<-RUBY).to include("should_compile", "and_this")
125
- if some_conditional
126
- :should_compile
127
- else
128
- :and_this
129
- end
130
- RUBY
131
- end
132
- end
133
-
134
- describe "pre-processed unless conditionals" do
135
- it "skips over if using RUBY_ENGINE/RUBY_PLATFORM == 'opal'" do
136
- expect_compiled(<<-RUBY).to_not include("should_not_compile")
137
- unless RUBY_ENGINE == 'opal'
138
- :should_not_compile
139
- end
140
- RUBY
141
- end
142
-
143
- it "generates unless code as normal if no check" do
144
- expect_compiled(<<-RUBY).to include("this_should_compile")
145
- unless this_is_true
146
- :this_should_compile
147
- end
148
- RUBY
149
- end
150
- end
151
-
152
- describe 'pre-processing require-ish methods' do
86
+ describe 'pre-processing require-ish methods' do
153
87
  describe '#require' do
154
88
  it 'parses and resolve #require argument' do
155
89
  compiler = compiler_for(%Q{require "#{__FILE__}"})
@@ -0,0 +1,2 @@
1
+ //= require required_file
2
+ console.log('file with directives');
@@ -0,0 +1 @@
1
+ console.log('required file');
@@ -23,39 +23,52 @@ describe "The def keyword" do
23
23
 
24
24
  describe "with normal args" do
25
25
  it "should list all args" do
26
- parsed("def foo(a); end")[3].should == [:args, :a]
27
- parsed("def foo(a, b); end")[3].should == [:args, :a, :b]
28
- parsed("def foo(a, b, c); end")[3].should == [:args, :a, :b, :c]
26
+ parsed("def foo(a); end")[3].should == [:args, [:arg, :a]]
27
+ parsed("def foo(a, b); end")[3].should == [:args, [:arg, :a], [:arg, :b]]
29
28
  end
30
29
  end
31
30
 
32
31
  describe "with opt args" do
33
32
  it "should list all opt args as well as block with each lasgn" do
34
- parsed("def foo(a = 1); end")[3].should == [:args, :a, [:block, [:lasgn, :a, [:int, 1]]]]
35
- parsed("def foo(a = 1, b = 2); end")[3].should == [:args, :a, :b, [:block, [:lasgn, :a, [:int, 1]], [:lasgn, :b, [:int, 2]]]]
36
- end
37
-
38
- it "should list lasgn block after all other args" do
39
- parsed("def foo(a, b = 1); end")[3].should == [:args, :a, :b, [:block, [:lasgn, :b, [:int, 1]]]]
40
- parsed("def foo(b = 1, *c); end")[3].should == [:args, :b, :"*c", [:block, [:lasgn, :b, [:int, 1]]]]
41
- parsed("def foo(b = 1, &block); end")[3].should == [:args, :b, :"&block", [:block, [:lasgn, :b, [:int, 1]]]]
33
+ parsed("def foo(a = 1); end")[3].should == [:args, [:optarg, :a, [:int, 1]]]
34
+ parsed("def foo(a = 1, b = 2); end")[3].should == [:args, [:optarg, :a, [:int, 1]], [:optarg, :b, [:int, 2]]]
42
35
  end
43
36
  end
44
37
 
45
38
  describe "with rest args" do
46
39
  it "should list rest args in place as a symbol with '*' prefix" do
47
- parsed("def foo(*a); end")[3].should == [:args, :"*a"]
40
+ parsed("def foo(*a); end")[3].should == [:args, [:restarg, :a]]
48
41
  end
49
42
 
50
43
  it "uses '*' as an arg name for rest args without a name" do
51
- parsed("def foo(*); end")[3].should == [:args, :"*"]
44
+ parsed("def foo(*); end")[3].should == [:args, [:restarg]]
52
45
  end
53
46
  end
54
47
 
55
48
  describe "with block arg" do
56
- it "should list block argument with the '&' prefix" do
57
- parsed("def foo(&a); end")[3].should == [:args, :"&a"]
49
+ it "should list block argument" do
50
+ parsed("def foo(&a); end")[3].should == [:args, [:blockarg, :a]]
58
51
  end
59
52
  end
60
- end
61
53
 
54
+ describe "with keyword args" do
55
+ it "should list all required keyword args" do
56
+ parsed("def foo(a:); end")[3].should == [:args, [:kwarg, :a]]
57
+ parsed("def foo(a:, b:); end")[3].should == [:args, [:kwarg, :a], [:kwarg, :b]]
58
+ end
59
+
60
+ it "should list all optional keyword args" do
61
+ parsed("def foo(a: 1); end")[3].should == [:args, [:kwoptarg, :a, [:int, 1]]]
62
+ parsed("def foo(a: 1, b: 2); end")[3].should == [:args, [:kwoptarg, :a, [:int, 1]], [:kwoptarg, :b, [:int, 2]]]
63
+ end
64
+
65
+ it "should list any keyword rest arg" do
66
+ parsed("def foo(**); end")[3].should == [:args, [:kwrestarg]]
67
+ parsed("def foo(**bar); end")[3].should == [:args, [:kwrestarg, :bar]]
68
+ end
69
+
70
+ it "should parse combinations of keyword args" do
71
+ parsed("def foo(a:, b: 1, **c); end")[3].should == [:args, [:kwarg, :a], [:kwoptarg, :b, [:int, 1]], [:kwrestarg, :c]]
72
+ end
73
+ end
74
+ end
@@ -27,20 +27,20 @@ describe Opal::Parser do
27
27
 
28
28
  describe "parses local variables inside a def" do
29
29
  it "should created by a norm arg" do
30
- parsed("def a(b); b; end").should == [:def, nil, :a, [:args, :b], [:block, [:lvar, :b]]]
31
- parsed("def a(b, c); c; end").should == [:def, nil, :a, [:args, :b, :c], [:block, [:lvar, :c]]]
30
+ parsed("def a(b); b; end").should == [:def, nil, :a, [:args, [:arg, :b]], [:block, [:lvar, :b]]]
31
+ parsed("def a(b, c); c; end").should == [:def, nil, :a, [:args, [:arg, :b], [:arg, :c]], [:block, [:lvar, :c]]]
32
32
  end
33
33
 
34
34
  it "should be created by an opt arg" do
35
- parsed("def a(b=10); b; end").should == [:def, nil, :a, [:args, :b, [:block, [:lasgn, :b, [:int, 10]]]], [:block, [:lvar, :b]]]
35
+ parsed("def a(b=10); b; end").should == [:def, nil, :a, [:args, [:optarg, :b, [:int, 10]]], [:block, [:lvar, :b]]]
36
36
  end
37
37
 
38
38
  it "should be created by a rest arg" do
39
- parsed("def a(*b); b; end").should == [:def, nil, :a, [:args, :"*b"], [:block, [:lvar, :b]]]
39
+ parsed("def a(*b); b; end").should == [:def, nil, :a, [:args, [:restarg, :b]], [:block, [:lvar, :b]]]
40
40
  end
41
41
 
42
42
  it "should be created by a block arg" do
43
- parsed("def a(&b); b; end").should == [:def, nil, :a, [:args, :"&b"], [:block, [:lvar, :b]]]
43
+ parsed("def a(&b); b; end").should == [:def, nil, :a, [:args, [:blockarg, :b]], [:block, [:lvar, :b]]]
44
44
  end
45
45
 
46
46
  it "should not be created from locals outside the def" do
@@ -3,17 +3,19 @@ require 'lib/shared/path_reader_shared'
3
3
  require 'opal/sprockets/path_reader'
4
4
 
5
5
  describe Opal::Sprockets::PathReader do
6
- subject(:path_reader) { described_class.new(env, context) }
7
-
8
- let(:env) { Sprockets::Environment.new.tap { |e| Opal.paths.each {|p| e.append_path(p)} } }
6
+ let(:env) { Sprockets::Environment.new }
9
7
  let(:context) { double('context', depend_on: nil, depend_on_asset: nil) }
10
-
11
- let(:logical_path) { 'sprockets_file' }
12
- let(:fixtures_dir) { File.expand_path('../../fixtures/', __FILE__) }
13
- let(:full_path) { File.join(fixtures_dir, logical_path+'.js.rb') }
14
8
  let(:contents) { File.read(full_path) }
9
+ let(:full_path) { fixtures_dir.join(logical_path+'.js.rb') }
10
+ let(:logical_path) { 'sprockets_file' }
11
+ let(:fixtures_dir) { Pathname('../../fixtures/').expand_path(__FILE__) }
12
+
13
+ subject(:path_reader) { described_class.new(env, context) }
15
14
 
16
- before { env.append_path fixtures_dir }
15
+ before do
16
+ Opal.paths.each {|p| env.append_path(p)}
17
+ env.append_path fixtures_dir
18
+ end
17
19
 
18
20
  include_examples :path_reader do
19
21
  let(:path) { logical_path }
@@ -22,4 +24,18 @@ describe Opal::Sprockets::PathReader do
22
24
  it 'can read stuff from sprockets env' do
23
25
  expect(path_reader.read(logical_path)).to eq(contents)
24
26
  end
27
+
28
+ it 'reads js files processing their directives' do
29
+ path = 'file_with_directives.js'
30
+ full_path = fixtures_dir.join(path)
31
+ required_contents = File.read(fixtures_dir.join('required_file.js')).strip
32
+ read_contents = path_reader.read(path)
33
+ actual_contents = full_path.read
34
+
35
+ expect(actual_contents).to include('//= require')
36
+ expect(read_contents).not_to include('//= require')
37
+
38
+ expect(read_contents).to include(required_contents)
39
+ expect(actual_contents).not_to include(required_contents)
40
+ end
25
41
  end
@@ -10,7 +10,7 @@ describe Opal::Server do
10
10
  s.main = 'opal'
11
11
  s.debug = false
12
12
  s.append_path File.expand_path('../../fixtures', __FILE__)
13
- s.sprockets.logger = Logger.new('/dev/null')
13
+ s.sprockets.logger = Logger.new(nil)
14
14
  }
15
15
  end
16
16
 
@@ -36,7 +36,7 @@ describe Opal::Server do
36
36
 
37
37
  expect(last_response).to be_ok
38
38
  received_map_path = extract_linked_map(last_response.body)
39
- expect(File.expand_path(received_map_path, js_path+'/..')).to eq(map_path)
39
+ expect(expand_path(received_map_path, js_path+'/..')).to eq(map_path)
40
40
 
41
41
  get '/assets/source_map/subfolder/other_file.map'
42
42
  expect(last_response).to be_ok
@@ -50,7 +50,7 @@ describe Opal::Server do
50
50
 
51
51
  expect(last_response).to be_ok
52
52
  received_map_path = extract_linked_map(last_response.body)
53
- expect(File.expand_path(received_map_path, js_path+'/..')).to eq(map_path)
53
+ expect(expand_path(received_map_path, js_path+'/..')).to eq(map_path)
54
54
 
55
55
 
56
56
  get '/assets/source_map/subfolder/other_file.map'
@@ -65,4 +65,11 @@ describe Opal::Server do
65
65
  expect(body).to match(source_map_comment_regexp)
66
66
  body.scan(source_map_comment_regexp).first.first
67
67
  end
68
+
69
+ def expand_path(file_name, dir_string)
70
+ path = File.expand_path(file_name, dir_string)
71
+ # Remove Windows letter and colon (eg. C:) from path
72
+ path = path[2..-1] if !(RUBY_PLATFORM =~ /mswin|mingw/).nil?
73
+ path
74
+ end
68
75
  end
@@ -34,6 +34,20 @@ describe Date do
34
34
  end
35
35
  end
36
36
 
37
+ describe '<=>' do
38
+ it 'returns -1 when self is less than other' do
39
+ (Date.new(2015, 1, 1) <=> Date.new(2015, 1, 2)).should == -1
40
+ end
41
+
42
+ it 'returns 0 when self is equal to other' do
43
+ (Date.new(2015, 1, 1) <=> Date.new(2015, 1, 1)).should == 0
44
+ end
45
+
46
+ it 'returns 1 when self is greater than other' do
47
+ (Date.new(2015, 1, 2) <=> Date.new(2015, 1, 1)).should == 1
48
+ end
49
+ end
50
+
37
51
  describe "#==" do
38
52
  it "returns true if self is equal to other date" do
39
53
  (Date.new(2013, 9, 13) == Date.new(2013, 9, 13)).should == true
@@ -0,0 +1,62 @@
1
+ # TODO: this should be loaded from rubyspec instead
2
+
3
+ describe "An instance method with keyword arguments" do
4
+ context "when there is a single keyword argument" do
5
+ before do
6
+ def foo(a: 1)
7
+ a
8
+ end
9
+ end
10
+
11
+ it "evaluates to the default when a value isn't provided" do
12
+ foo.should == 1
13
+ end
14
+
15
+ it "evaluates to the provided value" do
16
+ foo(a: 20).should == 20
17
+ foo(a: nil).should be_nil
18
+ end
19
+
20
+ it "raises an argument error when an unknown keyword argument is provided" do
21
+ lambda { foo(b: 20) }.should raise_error(ArgumentError)
22
+ end
23
+
24
+ it "raises an argument error when a non-keyword argument is provided" do
25
+ lambda { foo(1) }.should raise_error(ArgumentError)
26
+ end
27
+ end
28
+
29
+ it "treats a sole hash argument correctly" do
30
+ def foo(a, b: 10)
31
+ [a, b]
32
+ end
33
+ foo(b: "b").should == [{:b => "b"}, 10]
34
+ foo("a", b: "b").should == ["a", "b"]
35
+ end
36
+
37
+ it "correctly distinguishes between optional and keyword arguments" do
38
+ def foo(a = true, b: 10)
39
+ [a, b]
40
+ end
41
+ foo(b: 42).should == [true, 42]
42
+ foo(false, b: 42).should == [false, 42]
43
+ end
44
+
45
+ it "correctly distinguishes between rest and keyword arguments" do
46
+ def foo(*a, b: 10)
47
+ [a, b]
48
+ end
49
+ foo(1, 2, 3, 4).should == [[1, 2, 3, 4], 10]
50
+ foo(1, 2, 3, 4, b: 42).should == [[1, 2, 3, 4], 42]
51
+ foo(b: 42).should == [[], 42]
52
+ end
53
+
54
+ it "should allow keyword rest arguments" do
55
+ def foo(a: 1, **b)
56
+ [a, b]
57
+ end
58
+ foo(b: 2, c: 3, d: 4).should == [1, {:b => 2, :c => 3, :d => 4}]
59
+ foo(a: 4, b: 2).should == [4, {:b => 2}]
60
+ foo.should == [1, {}]
61
+ end
62
+ end