opal 0.3.44 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/CHANGELOG.md +52 -0
- data/README.md +3 -3
- data/Rakefile +32 -8
- data/bin/opal +69 -16
- data/config.ru +1 -1
- data/examples/native/app/app.rb +28 -9
- data/examples/rack/app/app.rb +1 -1
- data/lib/opal.rb +0 -1
- data/lib/opal/cli.rb +106 -0
- data/lib/opal/lexer.rb +4 -2
- data/lib/opal/parser.rb +603 -360
- data/lib/opal/processor.rb +20 -8
- data/lib/opal/server.rb +47 -0
- data/lib/opal/source_map.rb +63 -0
- data/lib/opal/sprockets_parser.rb +77 -0
- data/lib/opal/sprockets_source_map_header.rb +21 -0
- data/lib/opal/target_scope.rb +14 -7
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +2 -0
- data/opal/opal-browser/script_loader.rb +7 -7
- data/opal/opal-parser.js.erb +2 -2
- data/opal/opal-source-maps.js.erb +2 -0
- data/opal/opal.rb +3 -4
- data/opal/opal/array.rb +31 -28
- data/opal/opal/boolean.rb +4 -0
- data/opal/opal/class.rb +14 -5
- data/opal/opal/enumerable.rb +68 -8
- data/opal/opal/error.rb +1 -1
- data/opal/opal/hash.rb +15 -18
- data/opal/opal/kernel.rb +24 -10
- data/opal/opal/native.rb +31 -0
- data/opal/opal/nil_class.rb +7 -2
- data/opal/opal/numeric.rb +10 -1
- data/opal/opal/proc.rb +4 -0
- data/opal/opal/range.rb +1 -1
- data/opal/opal/regexp.rb +13 -3
- data/opal/opal/runtime.js +134 -51
- data/opal/opal/string.rb +45 -22
- data/opal/opal/time.rb +25 -7
- data/opal/source_map.rb +63 -0
- data/opal/source_map/generator.rb +251 -0
- data/opal/source_map/parser.rb +102 -0
- data/opal/source_map/vlq.rb +122 -0
- data/opal/strscan.rb +30 -12
- data/spec/opal/class/_inherited_spec.rb +1 -1
- data/spec/{rubyspec/core → opal}/class/bridge_class_spec.rb +5 -3
- data/spec/{rubyspec/core → opal}/class/extend_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/class/instance_methods_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/class/last_value_spec.rb +0 -1
- data/spec/{rubyspec/core → opal}/json/parse_spec.rb +0 -0
- data/spec/{rubyspec/core/kernel/block_given.rb → opal/kernel/block_given_spec.rb} +0 -0
- data/spec/{rubyspec/core → opal}/kernel/class_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/extend_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/format_spec.rb +0 -0
- data/spec/opal/kernel/freeze_spec.rb +15 -0
- data/spec/{rubyspec/core → opal}/kernel/match_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/method_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/methods_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/nil_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/p_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/printf_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/proc_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/rand_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/respond_to_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/sprintf_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/to_json_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/alias_method_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/ancestors_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/append_features_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/constants_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/module_function_spec.rb +0 -1
- data/spec/opal/native_spec.rb +85 -3
- data/spec/opal/numeric/equal_spec.rb +9 -0
- data/spec/opal/parser/irb_spec.rb +43 -0
- data/spec/{rubyspec/core → opal}/proc/proc_tricks_spec.rb +0 -0
- data/spec/opal/runtime/block_send_spec.rb +28 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/call_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/class_hierarchy_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/def_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/defined_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/super_spec.rb +0 -0
- data/spec/opal/source_map_spec.rb +19 -0
- data/spec/opal/string/freeze_spec.rb +15 -0
- data/spec/{rubyspec/core → opal}/string/to_json_spec.rb +0 -0
- data/spec/ospec/runner.rb +3 -0
- data/spec/parser/str_spec.rb +4 -0
- data/spec/rubyspec/core/enumerable/fixtures/classes.rb +2 -2
- data/spec/rubyspec/core/enumerable/none_spec.rb +68 -0
- data/spec/rubyspec/core/enumerable/sort_by_spec.rb +31 -0
- data/spec/rubyspec/core/hash/size_spec.rb +1 -1
- data/spec/rubyspec/core/hash/to_native_spec.rb +3 -3
- data/spec/rubyspec/core/string/fixtures/classes.rb +49 -0
- data/spec/rubyspec/core/string/index_spec.rb +405 -0
- data/spec/rubyspec/filters/bugs/language/class.rb +0 -2
- data/spec/rubyspec/filters/bugs/language/module.rb +3 -0
- data/spec/rubyspec/language/array_spec.rb +1 -1
- data/spec/rubyspec/language/block_spec.rb +1 -1
- data/spec/rubyspec/language/module_spec.rb +5 -5
- data/spec/rubyspec/language/predefined_spec.rb +1 -2
- data/spec/rubyspec/library/stringscanner/element_reference_spec.rb +29 -0
- data/spec/rubyspec/spec_helper.rb +31 -0
- metadata +130 -76
- data/lib/opal/erb.rb +0 -41
- data/opal/erb.rb +0 -19
- data/spec/opal/erb/erb_spec.rb +0 -31
- data/spec/simple_erb_template.opalerb +0 -1
- data/spec/templates/foo/bar.opalerb +0 -1
- data/spec/templates/prefixed.opalerb +0 -1
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Opal::Parser do
|
4
|
+
describe "irb parser option" do
|
5
|
+
before do
|
6
|
+
@parser = Opal::Parser.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "creates Opal.irb_vars if it does not exist" do
|
10
|
+
$global["Opal"].irb_vars = nil
|
11
|
+
opal_eval_compiled(@parser.parse "nil", :irb => true)
|
12
|
+
|
13
|
+
($global["Opal"].irb_vars == nil).should be_false
|
14
|
+
end
|
15
|
+
|
16
|
+
it "does not create Opal.irb_vars if :irb option not passed" do
|
17
|
+
$global["Opal"].irb_vars = nil
|
18
|
+
opal_eval_compiled(@parser.parse "nil")
|
19
|
+
|
20
|
+
($global["Opal"].irb_vars == nil).should be_true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "sets each s(:lasgn) in the top level onto irb_vars" do
|
24
|
+
opal_eval_compiled @parser.parse "foo = 42", :irb => true
|
25
|
+
$global["Opal"].irb_vars.foo.should == 42
|
26
|
+
end
|
27
|
+
|
28
|
+
it "gets each s(:lvar) in the top level from irb_vars" do
|
29
|
+
opal_eval_compiled @parser.parse "foo = 3.142; bar = foo", :irb => true
|
30
|
+
$global["Opal"].irb_vars.bar.should == 3.142
|
31
|
+
end
|
32
|
+
|
33
|
+
it "persists local vars between parses" do
|
34
|
+
opal_eval_compiled @parser.parse "foo = 'hello world'", :irb => true
|
35
|
+
opal_eval_compiled @parser.parse "bar = foo.upcase", :irb => true
|
36
|
+
$global["Opal"].irb_vars.bar.should == "HELLO WORLD"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "can still call top level methods" do
|
40
|
+
opal_eval_compiled(@parser.parse("to_s", :irb => true)).should == "main"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class RuntimeOpalBlockSendSpec
|
4
|
+
def simple
|
5
|
+
42
|
6
|
+
end
|
7
|
+
|
8
|
+
def yielder(&block)
|
9
|
+
yield 3.142
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Opal.block_send()" do
|
14
|
+
before do
|
15
|
+
@obj = RuntimeOpalBlockSendSpec.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it "calls receiver with given method" do
|
19
|
+
`Opal.block_send(#{@obj}, 'simple')`.should == 42
|
20
|
+
end
|
21
|
+
|
22
|
+
it "calls method with given block" do
|
23
|
+
val = nil
|
24
|
+
p = proc { |a| val = a }
|
25
|
+
`Opal.block_send(#{@obj}, 'yielder', p)`
|
26
|
+
val.should == 3.142
|
27
|
+
end
|
28
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'opal-source-maps'
|
3
|
+
|
4
|
+
describe Opal::SourceMap do
|
5
|
+
before do
|
6
|
+
pathname = 'foo.rb'
|
7
|
+
@source = Opal.parse('1 + 1', pathname)
|
8
|
+
@map = Opal::SourceMap.new(@source, pathname)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'source has the magic comments' do
|
12
|
+
Opal::SourceMap::FILE_REGEXP.should =~ @source
|
13
|
+
Opal::SourceMap::LINE_REGEXP.should =~ @source
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not blow while generating the map' do
|
17
|
+
lambda { @map.as_json }.should_not raise_error
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Just accepting reality of immutability
|
2
|
+
|
3
|
+
describe "String#freeze" do
|
4
|
+
it "is always frozen" do
|
5
|
+
s = "a string"
|
6
|
+
s.frozen?.should be_true
|
7
|
+
s.freeze
|
8
|
+
s.frozen?.should be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns self" do
|
12
|
+
s = "a string"
|
13
|
+
s.freeze.should equal(s)
|
14
|
+
end
|
15
|
+
end
|
File without changes
|
data/spec/ospec/runner.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
require 'date'
|
3
3
|
require 'observer'
|
4
4
|
|
5
|
+
ENV['MSPEC_RUNNER'] = true
|
6
|
+
|
5
7
|
class OSpecFilter
|
6
8
|
def self.main
|
7
9
|
@main ||= self.new
|
@@ -176,6 +178,7 @@ module Kernel
|
|
176
178
|
# FIXME: remove
|
177
179
|
def ruby_version_is(*); end
|
178
180
|
def pending(*); end
|
181
|
+
def language_version(*); end
|
179
182
|
end
|
180
183
|
|
181
184
|
module MSpec
|
data/spec/parser/str_spec.rb
CHANGED
@@ -99,5 +99,9 @@ describe "Strings" do
|
|
99
99
|
opal_parse("?a").should == [:str, "a"]
|
100
100
|
opal_parse("?&").should == [:str, "&"]
|
101
101
|
end
|
102
|
+
|
103
|
+
it "parses a string sexp as a command arg" do
|
104
|
+
opal_parse("foo ?a").should == [:call, nil, :foo, [:arglist, [:str, "a"]]]
|
105
|
+
end
|
102
106
|
end
|
103
107
|
end
|
@@ -120,14 +120,14 @@ module EnumerableSpecs
|
|
120
120
|
@values
|
121
121
|
end
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
class EnumConvertable
|
125
125
|
attr_accessor :called
|
126
126
|
attr_accessor :sym
|
127
127
|
def initialize(delegate)
|
128
128
|
@delegate = delegate
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
def to_enum(sym)
|
132
132
|
self.called = :to_enum
|
133
133
|
self.sym = sym
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
require File.expand_path('../fixtures/classes', __FILE__)
|
3
|
+
|
4
|
+
#ruby_version_is "1.8.7" do
|
5
|
+
describe "Enumerable#none?" do
|
6
|
+
it "returns true if none of the elements in self are true" do
|
7
|
+
e = EnumerableSpecs::Numerous.new(false, nil, false)
|
8
|
+
e.none?.should be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false if at least one of the elements in self are true" do
|
12
|
+
e = EnumerableSpecs::Numerous.new(false, nil, true, false)
|
13
|
+
e.none?.should be_false
|
14
|
+
end
|
15
|
+
|
16
|
+
it "gathers whole arrays as elements when each yields multiple" do
|
17
|
+
multi = EnumerableSpecs::YieldsMultiWithFalse.new
|
18
|
+
multi.none?.should be_false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "Enumerable#none? with a block" do
|
23
|
+
before(:each) do
|
24
|
+
@e = EnumerableSpecs::Numerous.new(1,1,2,3,4)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "passes each element to the block in turn until it returns true" do
|
28
|
+
acc = []
|
29
|
+
@e.none? {|e| acc << e; false }
|
30
|
+
acc.should == [1,1,2,3,4]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "stops passing elements to the block when it returns true" do
|
34
|
+
acc = []
|
35
|
+
@e.none? {|e| acc << e; e == 3 ? true : false }
|
36
|
+
acc.should == [1,1,2,3]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns true if the block never returns true" do
|
40
|
+
@e.none? {|e| false }.should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns false if the block ever returns true" do
|
44
|
+
@e.none? {|e| e == 3 ? true : false }.should be_false
|
45
|
+
end
|
46
|
+
|
47
|
+
ruby_version_is ""..."1.9" do
|
48
|
+
it "gathers whole arrays as elements when each yields multiple" do
|
49
|
+
multi = EnumerableSpecs::YieldsMulti.new
|
50
|
+
multi.none? {|e| e == 1 }.should be_true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
ruby_version_is "1.9" do
|
55
|
+
it "gathers initial args as elements when each yields multiple" do
|
56
|
+
multi = EnumerableSpecs::YieldsMulti.new
|
57
|
+
multi.none? {|e| e == [1, 2] }.should be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "yields multiple arguments when each yields multiple" do
|
62
|
+
multi = EnumerableSpecs::YieldsMulti.new
|
63
|
+
yielded = []
|
64
|
+
multi.none? {|e, i| yielded << [e, i] }
|
65
|
+
yielded.should == [[1, 2]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
#end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
require File.expand_path('../fixtures/classes', __FILE__)
|
3
|
+
|
4
|
+
describe "Enumerable#sort_by" do
|
5
|
+
it "returns an array of elements ordered by the result of block" do
|
6
|
+
a = EnumerableSpecs::Numerous.new("once", "upon", "a", "time")
|
7
|
+
a.sort_by { |i| i[0] }.should == ["a", "once", "time", "upon"]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sorts the object by the given attribute" do
|
11
|
+
a = EnumerableSpecs::SortByDummy.new("fooo")
|
12
|
+
b = EnumerableSpecs::SortByDummy.new("bar")
|
13
|
+
|
14
|
+
ar = [a, b].sort_by { |d| d.s }
|
15
|
+
ar.should == [b, a]
|
16
|
+
end
|
17
|
+
|
18
|
+
ruby_version_is "1.8.7" do
|
19
|
+
it "returns an Enumerator when a block is not supplied" do
|
20
|
+
a = EnumerableSpecs::Numerous.new("a","b")
|
21
|
+
a.sort_by.should be_an_instance_of(enumerator_class)
|
22
|
+
a.to_a.should == ["a", "b"]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "gathers whole arrays as elements when each yields multiple" do
|
27
|
+
# TODO: fix support for yielding multiple values (see fixtures/classes)
|
28
|
+
multi = EnumerableSpecs::YieldsMulti.new
|
29
|
+
multi.sort_by {|e| e.size}.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
|
30
|
+
end
|
31
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
describe "Hash#
|
1
|
+
describe "Hash#to_n" do
|
2
2
|
it "should return a js object representing hash" do
|
3
|
-
Hash.
|
3
|
+
Hash.new({:a => 100, :b => 200}.to_n).should == {:a => 100, :b => 200}
|
4
4
|
end
|
5
|
-
end
|
5
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Object
|
2
|
+
# This helper is defined here rather than in MSpec because
|
3
|
+
# it is only used in #unpack specs.
|
4
|
+
def unpack_format(count=nil, repeat=nil)
|
5
|
+
format = "#{instance_variable_get(:@method)}#{count}"
|
6
|
+
format *= repeat if repeat
|
7
|
+
format
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module StringSpecs
|
12
|
+
class MyString < String; end
|
13
|
+
class MyArray < Array; end
|
14
|
+
class MyRange < Range; end
|
15
|
+
|
16
|
+
class SubString < String
|
17
|
+
attr_reader :special
|
18
|
+
|
19
|
+
def initialize(str=nil)
|
20
|
+
@special = str
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class InitializeString < String
|
25
|
+
attr_reader :ivar
|
26
|
+
|
27
|
+
def initialize(other)
|
28
|
+
super
|
29
|
+
@ivar = 1
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize_copy(other)
|
33
|
+
ScratchPad.record object_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module StringModule
|
38
|
+
def repr
|
39
|
+
1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class StringWithRaisingConstructor < String
|
44
|
+
def initialize(str)
|
45
|
+
raise ArgumentError.new('constructor was called') unless str == 'silly:string'
|
46
|
+
self.replace(str)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,405 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
3
|
+
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
4
|
+
|
5
|
+
describe "String#index" do
|
6
|
+
it "raises a TypeError if passed nil" do
|
7
|
+
lambda { "abc".index nil }.should raise_error(TypeError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "raises a TypeError if passed a boolean" do
|
11
|
+
lambda { "abc".index true }.should raise_error(TypeError)
|
12
|
+
end
|
13
|
+
|
14
|
+
not_compliant_on :opal do
|
15
|
+
it "raises a TypeError if passed a Symbol" do
|
16
|
+
lambda { "abc".index :a }.should raise_error(TypeError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "calls #to_str to convert the first argument" do
|
20
|
+
char = mock("string index char")
|
21
|
+
char.should_receive(:to_str).and_return("b")
|
22
|
+
"abc".index(char).should == 1
|
23
|
+
end
|
24
|
+
|
25
|
+
it "calls #to_int to convert the second argument" do
|
26
|
+
offset = mock("string index offset")
|
27
|
+
offset.should_receive(:to_int).and_return(1)
|
28
|
+
"abc".index("c", offset).should == 2
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
ruby_version_is ""..."1.9" do
|
33
|
+
it "does not call #to_int to convert the first argument" do
|
34
|
+
char = mock("string index char")
|
35
|
+
char.should_not_receive(:to_int)
|
36
|
+
lambda { "abc".index char }.should raise_error(TypeError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ruby_version_is "1.9" do
|
41
|
+
it "raises a TypeError if passed a Fixnum" do
|
42
|
+
lambda { "abc".index 97 }.should raise_error(TypeError)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
ruby_version_is ""..."1.9" do
|
48
|
+
describe "String#index with Fixnum" do
|
49
|
+
it "returns the index of the first occurrence of the given character" do
|
50
|
+
"hello".index(?e).should == 1
|
51
|
+
"hello".index(?l).should == 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it "character values over 255 (256th ASCII character) always result in nil" do
|
55
|
+
# A naive implementation could try to use % 256
|
56
|
+
"hello".index(?e + 256 * 3).should == nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "negative character values always result in nil" do
|
60
|
+
# A naive implementation could try to use % 256
|
61
|
+
"hello".index(-(256 - ?e)).should == nil
|
62
|
+
end
|
63
|
+
|
64
|
+
it "starts the search at the given offset" do
|
65
|
+
"blablabla".index(?b, 0).should == 0
|
66
|
+
"blablabla".index(?b, 1).should == 3
|
67
|
+
"blablabla".index(?b, 2).should == 3
|
68
|
+
"blablabla".index(?b, 3).should == 3
|
69
|
+
"blablabla".index(?b, 4).should == 6
|
70
|
+
"blablabla".index(?b, 5).should == 6
|
71
|
+
"blablabla".index(?b, 6).should == 6
|
72
|
+
|
73
|
+
"blablabla".index(?a, 0).should == 2
|
74
|
+
"blablabla".index(?a, 2).should == 2
|
75
|
+
"blablabla".index(?a, 3).should == 5
|
76
|
+
"blablabla".index(?a, 4).should == 5
|
77
|
+
"blablabla".index(?a, 5).should == 5
|
78
|
+
"blablabla".index(?a, 6).should == 8
|
79
|
+
"blablabla".index(?a, 7).should == 8
|
80
|
+
"blablabla".index(?a, 8).should == 8
|
81
|
+
end
|
82
|
+
|
83
|
+
it "starts the search at offset + self.length if offset is negative" do
|
84
|
+
str = "blablabla"
|
85
|
+
|
86
|
+
[?a, ?b].each do |needle|
|
87
|
+
(-str.length .. -1).each do |offset|
|
88
|
+
p offset
|
89
|
+
str.index(needle, offset).should ==
|
90
|
+
str.index(needle, offset + str.length)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
"blablabla".index(?b, -9).should == 0
|
95
|
+
end
|
96
|
+
|
97
|
+
it "returns nil if offset + self.length is < 0 for negative offsets" do
|
98
|
+
"blablabla".index(?b, -10).should == nil
|
99
|
+
"blablabla".index(?b, -20).should == nil
|
100
|
+
end
|
101
|
+
|
102
|
+
it "returns nil if the character isn't found" do
|
103
|
+
"hello".index(0).should == nil
|
104
|
+
|
105
|
+
"hello".index(?H).should == nil
|
106
|
+
"hello".index(?z).should == nil
|
107
|
+
"hello".index(?e, 2).should == nil
|
108
|
+
|
109
|
+
"blablabla".index(?b, 7).should == nil
|
110
|
+
"blablabla".index(?b, 10).should == nil
|
111
|
+
|
112
|
+
"blablabla".index(?a, 9).should == nil
|
113
|
+
"blablabla".index(?a, 20).should == nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "String#index with String" do
|
119
|
+
it "behaves the same as String#index(char) for one-character strings" do
|
120
|
+
["blablabla", "hello cruel world...!"].each do |str|
|
121
|
+
str.split("").uniq.each do |str|
|
122
|
+
chr = str[0]
|
123
|
+
str.index(str).should == str.index(chr)
|
124
|
+
|
125
|
+
0.upto(str.size + 1) do |start|
|
126
|
+
str.index(str, start).should == str.index(chr, start)
|
127
|
+
end
|
128
|
+
|
129
|
+
(-str.size - 1).upto(-1) do |start|
|
130
|
+
str.index(str, start).should == str.index(chr, start)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it "returns the index of the first occurrence of the given substring" do
|
137
|
+
"blablabla".index("").should == 0
|
138
|
+
"blablabla".index("b").should == 0
|
139
|
+
"blablabla".index("bla").should == 0
|
140
|
+
"blablabla".index("blabla").should == 0
|
141
|
+
"blablabla".index("blablabla").should == 0
|
142
|
+
|
143
|
+
"blablabla".index("l").should == 1
|
144
|
+
"blablabla".index("la").should == 1
|
145
|
+
"blablabla".index("labla").should == 1
|
146
|
+
"blablabla".index("lablabla").should == 1
|
147
|
+
|
148
|
+
"blablabla".index("a").should == 2
|
149
|
+
"blablabla".index("abla").should == 2
|
150
|
+
"blablabla".index("ablabla").should == 2
|
151
|
+
end
|
152
|
+
|
153
|
+
it "doesn't set $~" do
|
154
|
+
$~ = nil
|
155
|
+
|
156
|
+
'hello.'.index('ll')
|
157
|
+
$~.should == nil
|
158
|
+
end
|
159
|
+
|
160
|
+
it "ignores string subclasses" do
|
161
|
+
"blablabla".index(StringSpecs::MyString.new("bla")).should == 0
|
162
|
+
StringSpecs::MyString.new("blablabla").index("bla").should == 0
|
163
|
+
StringSpecs::MyString.new("blablabla").index(StringSpecs::MyString.new("bla")).should == 0
|
164
|
+
end
|
165
|
+
|
166
|
+
it "starts the search at the given offset" do
|
167
|
+
"blablabla".index("bl", 0).should == 0
|
168
|
+
"blablabla".index("bl", 1).should == 3
|
169
|
+
"blablabla".index("bl", 2).should == 3
|
170
|
+
"blablabla".index("bl", 3).should == 3
|
171
|
+
|
172
|
+
"blablabla".index("bla", 0).should == 0
|
173
|
+
"blablabla".index("bla", 1).should == 3
|
174
|
+
"blablabla".index("bla", 2).should == 3
|
175
|
+
"blablabla".index("bla", 3).should == 3
|
176
|
+
|
177
|
+
"blablabla".index("blab", 0).should == 0
|
178
|
+
"blablabla".index("blab", 1).should == 3
|
179
|
+
"blablabla".index("blab", 2).should == 3
|
180
|
+
"blablabla".index("blab", 3).should == 3
|
181
|
+
|
182
|
+
"blablabla".index("la", 1).should == 1
|
183
|
+
"blablabla".index("la", 2).should == 4
|
184
|
+
"blablabla".index("la", 3).should == 4
|
185
|
+
"blablabla".index("la", 4).should == 4
|
186
|
+
|
187
|
+
"blablabla".index("lab", 1).should == 1
|
188
|
+
"blablabla".index("lab", 2).should == 4
|
189
|
+
"blablabla".index("lab", 3).should == 4
|
190
|
+
"blablabla".index("lab", 4).should == 4
|
191
|
+
|
192
|
+
"blablabla".index("ab", 2).should == 2
|
193
|
+
"blablabla".index("ab", 3).should == 5
|
194
|
+
"blablabla".index("ab", 4).should == 5
|
195
|
+
"blablabla".index("ab", 5).should == 5
|
196
|
+
|
197
|
+
"blablabla".index("", 0).should == 0
|
198
|
+
"blablabla".index("", 1).should == 1
|
199
|
+
"blablabla".index("", 2).should == 2
|
200
|
+
"blablabla".index("", 7).should == 7
|
201
|
+
"blablabla".index("", 8).should == 8
|
202
|
+
"blablabla".index("", 9).should == 9
|
203
|
+
end
|
204
|
+
|
205
|
+
it "starts the search at offset + self.length if offset is negative" do
|
206
|
+
str = "blablabla"
|
207
|
+
|
208
|
+
["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
|
209
|
+
(-str.length .. -1).each do |offset|
|
210
|
+
str.index(needle, offset).should ==
|
211
|
+
str.index(needle, offset + str.length)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
it "returns nil if the substring isn't found" do
|
217
|
+
"blablabla".index("B").should == nil
|
218
|
+
"blablabla".index("z").should == nil
|
219
|
+
"blablabla".index("BLA").should == nil
|
220
|
+
"blablabla".index("blablablabla").should == nil
|
221
|
+
"blablabla".index("", 10).should == nil
|
222
|
+
"blablabla".index("", 10).should == nil
|
223
|
+
|
224
|
+
"12345".index("", 6).should == nil
|
225
|
+
"hello".index("he", 1).should == nil
|
226
|
+
"hello".index("he", 2).should == nil
|
227
|
+
end
|
228
|
+
|
229
|
+
with_feature :encoding do
|
230
|
+
it "returns the character index of a multibyte character" do
|
231
|
+
"ありがとう".index("が").should == 2
|
232
|
+
end
|
233
|
+
|
234
|
+
it "returns the character index after offset" do
|
235
|
+
"われわれ".index("わ", 1).should == 2
|
236
|
+
end
|
237
|
+
|
238
|
+
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
|
239
|
+
char = "れ".encode Encoding::EUC_JP
|
240
|
+
lambda do
|
241
|
+
"あれ".index char
|
242
|
+
end.should raise_error(Encoding::CompatibilityError)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "String#index with Regexp" do
|
248
|
+
it "behaves the same as String#index(string) for escaped string regexps" do
|
249
|
+
["blablabla", "hello cruel world...!"].each do |str|
|
250
|
+
["", "b", "bla", "lab", "o c", "d."].each do |needle|
|
251
|
+
regexp = Regexp.new(Regexp.escape(needle))
|
252
|
+
str.index(regexp).should == str.index(needle)
|
253
|
+
|
254
|
+
0.upto(str.size + 1) do |start|
|
255
|
+
str.index(regexp, start).should == str.index(needle, start)
|
256
|
+
end
|
257
|
+
|
258
|
+
(-str.size - 1).upto(-1) do |start|
|
259
|
+
str.index(regexp, start).should == str.index(needle, start)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
it "returns the index of the first match of regexp" do
|
266
|
+
"blablabla".index(/bla/).should == 0
|
267
|
+
"blablabla".index(/BLA/i).should == 0
|
268
|
+
|
269
|
+
"blablabla".index(/.{0}/).should == 0
|
270
|
+
"blablabla".index(/.{6}/).should == 0
|
271
|
+
"blablabla".index(/.{9}/).should == 0
|
272
|
+
|
273
|
+
"blablabla".index(/.*/).should == 0
|
274
|
+
"blablabla".index(/.+/).should == 0
|
275
|
+
|
276
|
+
"blablabla".index(/lab|b/).should == 0
|
277
|
+
|
278
|
+
not_compliant_on :opal do
|
279
|
+
"blablabla".index(/\A/).should == 0
|
280
|
+
"blablabla".index(/\Z/).should == 9
|
281
|
+
"blablabla".index(/\z/).should == 9
|
282
|
+
"blablabla\n".index(/\Z/).should == 9
|
283
|
+
"blablabla\n".index(/\z/).should == 10
|
284
|
+
end
|
285
|
+
|
286
|
+
"blablabla".index(/^/).should == 0
|
287
|
+
"\nblablabla".index(/^/).should == 0
|
288
|
+
|
289
|
+
not_compliant_on :opal do
|
290
|
+
"b\nablabla".index(/$/).should == 1
|
291
|
+
"bl\nablabla".index(/$/).should == 2
|
292
|
+
end
|
293
|
+
|
294
|
+
"blablabla".index(/.l./).should == 0
|
295
|
+
end
|
296
|
+
|
297
|
+
it "sets $~ to MatchData of match and nil when there's none" do
|
298
|
+
'hello.'.index(/.(.)/)
|
299
|
+
$~[0].should == 'he'
|
300
|
+
|
301
|
+
'hello.'.index(/not/)
|
302
|
+
$~.should == nil
|
303
|
+
end
|
304
|
+
|
305
|
+
it "starts the search at the given offset" do
|
306
|
+
"blablabla".index(/.{0}/, 5).should == 5
|
307
|
+
"blablabla".index(/.{1}/, 5).should == 5
|
308
|
+
"blablabla".index(/.{2}/, 5).should == 5
|
309
|
+
"blablabla".index(/.{3}/, 5).should == 5
|
310
|
+
"blablabla".index(/.{4}/, 5).should == 5
|
311
|
+
|
312
|
+
"blablabla".index(/.{0}/, 3).should == 3
|
313
|
+
"blablabla".index(/.{1}/, 3).should == 3
|
314
|
+
"blablabla".index(/.{2}/, 3).should == 3
|
315
|
+
"blablabla".index(/.{5}/, 3).should == 3
|
316
|
+
"blablabla".index(/.{6}/, 3).should == 3
|
317
|
+
|
318
|
+
"blablabla".index(/.l./, 0).should == 0
|
319
|
+
"blablabla".index(/.l./, 1).should == 3
|
320
|
+
"blablabla".index(/.l./, 2).should == 3
|
321
|
+
"blablabla".index(/.l./, 3).should == 3
|
322
|
+
|
323
|
+
"xblaxbla".index(/x./, 0).should == 0
|
324
|
+
"xblaxbla".index(/x./, 1).should == 4
|
325
|
+
"xblaxbla".index(/x./, 2).should == 4
|
326
|
+
|
327
|
+
not_compliant_on :opal do
|
328
|
+
"blablabla\n".index(/\Z/, 9).should == 9
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it "starts the search at offset + self.length if offset is negative" do
|
333
|
+
str = "blablabla"
|
334
|
+
|
335
|
+
["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
|
336
|
+
(-str.length .. -1).each do |offset|
|
337
|
+
str.index(needle, offset).should ==
|
338
|
+
str.index(needle, offset + str.length)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
it "returns nil if the substring isn't found" do
|
344
|
+
"blablabla".index(/BLA/).should == nil
|
345
|
+
|
346
|
+
"blablabla".index(/.{10}/).should == nil
|
347
|
+
"blaxbla".index(/.x/, 3).should == nil
|
348
|
+
"blaxbla".index(/..x/, 2).should == nil
|
349
|
+
end
|
350
|
+
|
351
|
+
it "returns nil if the Regexp matches the empty string and the offset is out of range" do
|
352
|
+
"ruby".index(//,12).should be_nil
|
353
|
+
end
|
354
|
+
|
355
|
+
not_compliant_on :opal do
|
356
|
+
it "supports \\G which matches at the given start offset" do
|
357
|
+
"helloYOU.".index(/\GYOU/, 5).should == 5
|
358
|
+
"helloYOU.".index(/\GYOU/).should == nil
|
359
|
+
|
360
|
+
re = /\G.+YOU/
|
361
|
+
# The # marks where \G will match.
|
362
|
+
[
|
363
|
+
["#hi!YOUall.", 0],
|
364
|
+
["h#i!YOUall.", 1],
|
365
|
+
["hi#!YOUall.", 2],
|
366
|
+
["hi!#YOUall.", nil]
|
367
|
+
].each do |spec|
|
368
|
+
|
369
|
+
start = spec[0].index("#")
|
370
|
+
str = spec[0].delete("#")
|
371
|
+
|
372
|
+
str.index(re, start).should == spec[1]
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
not_compliant_on :opal do
|
378
|
+
it "converts start_offset to an integer via to_int" do
|
379
|
+
obj = mock('1')
|
380
|
+
obj.should_receive(:to_int).and_return(1)
|
381
|
+
"RWOARW".index(/R./, obj).should == 4
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
with_feature :encoding do
|
386
|
+
it "returns the character index of a multibyte character" do
|
387
|
+
"ありがとう".index(/が/).should == 2
|
388
|
+
end
|
389
|
+
|
390
|
+
it "returns the character index after offset" do
|
391
|
+
"われわれ".index(/わ/, 1).should == 2
|
392
|
+
end
|
393
|
+
|
394
|
+
it "treats the offset as a character index" do
|
395
|
+
"われわわれ".index(/わ/, 3).should == 3
|
396
|
+
end
|
397
|
+
|
398
|
+
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
|
399
|
+
re = Regexp.new "れ".encode(Encoding::EUC_JP)
|
400
|
+
lambda do
|
401
|
+
"あれ".index re
|
402
|
+
end.should raise_error(Encoding::CompatibilityError)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|