The Rubinius project generally uses TDD/BDD-style executable specifications to drive development. The Rubinius spec directory is generally conceptually divided into two parts:
-
All the files under
spec/rubythat describe the behavior of MatzRuby -
And all the other files under the
specdirectory that describe the behavior of Rubinius
Since the Rubinius spec directory is a hybrid, see Howto - Develop with a separate RubySpec repo for more explicit, step-by-step instructions.
Organization
The Rubinius specs follow the same general organization (although in different directories) and style as the RubySpecs. So, a good place to start is by reading through the RubySpec documentation.
Ruby specs
The Rubinius repository contains two copies of the RubySpecs. The spec/frozen directory is a git submodule of the RubySpec repository. The submodule is literally frozen to a particular revision of the RubySpecs. This revision is synchronized with the tag files in the spec/tags/frozen directory. The spec/frozen files are used by the CI (continuous integration) runner (@mspec/bin/mspec-ci@, invoked by rake spec or bin/mspec ci). The CI specs are run before any changes are pushed to ensure that no new code causes regressions. Since Rubinius does not pass all existing RubySpecs, the tags in the spec/tags/frozen directory exclude known failures.
The Rubinius repository also contains a clone of the RubySpecs repository in the spec/ruby directory. This clone is included for the convenience of making changes to the RubySpec files directly.
Rubinius specs
All the other directories under the spec directory except for spec/ruby and spec/frozen are for specs specific to Rubinius. The directories are self-explanatory. For example, the spec/compiler directory is for specs for the Rubinius compiler.
Three directories could be confusing so those are described in more detail here.
spec/core
This directory is for Rubinius specific extensions to MatzRuby core library. For example, Rubinius has a Tuple and ByteArray class. The specs for these are under the spec/core directory. This directory is also for Rubinius specific extensions to methods of the MatzRuby core library classes. For example, Rubinius handles coercion of Bignum and other numeric differently. The spec/core directory parallels the purpose of the spec/ruby/1.8/core directory from the RubySpecs.
spec/language
Again, this directory contains Rubinius specific specs related to the Ruby language. The directory parallels the spec/ruby/1.8/language directory.
spec/library
This directory contains Rubinius specific standard library classes (e.g. Actor, VMActor) and Rubinius specific behavior of methods of MatzRuby standard library classes.
Subtend
Subtend is the Rubinius component that provides a C API compatible with MRI. Writing specs for the subtend functions involves writing a C extension. Review the following example for doing this. Note the following:
- The specs are wrapped in an "extension :rubinius" block to only be executed by Rubinius.
- The "compile_extension" helper is used to compile the C extension.
- The C extension is required after it is compiled.
- The rb_ary_xxx methods on SubtendArray are not the C rb_ary_xxx methods. They are just a convention that helps the specs document which C function is being referenced.
- The rb_ary_xxx methods are defined in the C extension and map to sa_ary_xxx functions.
(Note: This example is only partially accurate for how the existing specs are written. However, this documents the expected conventions. The actual specs will be updated shortly.)
spec/subtend/array_spec.rb
require File.dirname(__FILE__) + '/../spec_helper'
require File.dirname(__FILE__) + '/subtend_helper'
compile_extension('subtend_array')
require File.dirname(__FILE__) + '/ext/subtend_array'
describe "SubtendArray" do
before :each do
@s = SubtendArray.new
end
it "rb_ary_new should return an empty array" do
@s.new_array.should == []
end
it "rb_ary_push should add an element to an array" do
@s.rb_ary_push([], 4).should == [4]
end
it "rb_ary_push2 should add elements to an array" do
o = mock('x')
@s.rb_ary_push2([], 4, o).should == [4,o]
end
it "rb_ary_pop should remove the last element in the array and return it" do
a = [1,2,3]
@s.rb_ary_pop(a).should == 3
a.should == [1,2]
end
it "rb_ary_join should join elements of an array with a string" do
a = [1,2,3]
b = ","
@s.rb_ary_join(a,b).should == "1,2,3"
end
# ...
end
spec/subtend/ext/subtend_array.c
static VALUE sa_array_store(VALUE self, VALUE array, VALUE offset, VALUE value) {
rb_ary_store(array, FIX2INT(offset), value);
return Qnil;
}
void Init_subtend_array() {
VALUE cls;
cls = rb_define_class("SubtendArray", rb_cObject);
rb_define_method(cls, "new_array", sa_new_array, 0);
rb_define_method(cls, "rb_ary_store", sa_array_store, 3);
}
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
0.10—69% complete
Completed 9 of 13 tickets
Pages
- Home
- FAQ
- IRC Info and Who's Who
- Releases
- Using Git
- Installation
- Getting Started
- Common Build Problems and Solutions
- Howto - Contribute
- Howto - Write a ticket
- Howto - Run my Rails app with Rubinius
- Howto - Write a Ruby spec
- Howto - Write a Rubinius spec
- Howto - Fix a failing spec
- Howto - Develop with a separate RubySpec repo
- Howto - Debug shotgun
- The Rubinius specs
- Shotgun - The Rubinius Virtual Machine
- Developer Readme
- Core Library - Coding Guidelines
- Coding Style Guide
- Contributor Platforms
- Stuff to read
- Extending Standard Library Specs
- Improve Gem Support in Rubinius
- Actors - Concurrent Rubinius
- FFI or Foreign Function Interface
- Adding Dir to C++ VM
