Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ puts obj.raw_hash.inspect
#### Object
`Ruby::Marshal.load(::Class, IO)` and `Ruby::Marshal.load(::Class, ::String)` are provided as convenience methods for unmarshalling straight into a Crystal object. Any class passed to these methods must implement `#initialize(obj : ::Ruby::Marshal::StreamObject)` in order to read the marshalled data.

The `ruby_marshal_properties` macro is provided as a convenience for simple marshalled objects. It will auto-unmarshal for you provided the correct schema for the data.
The `Ruby::Marshal.mapping` macro is provided as a convenience for simple marshalled objects. It will auto-unmarshal for you provided the correct schema for the data.

Unlike the other datatypes, `#data` in the case of objects will return a `Ruby::Marshall::Null` object. To use an unmarshalled object, cast to `Ruby::Marshal::Object`. You can then reach the data by means of `#read_raw_attr(::String)` or `#read_attr(::String)`.

Expand Down Expand Up @@ -284,10 +284,9 @@ obj = Ruby::Marshal.load( User, File.read("marshalled-valid.out") )
puts obj.inspect
#=> #<User:0x10d5c85a0 @id=1, @name="Test">

# As a convenience to setting these classes up, use the `ruby_marshal_properties` helper macro
# As a convenience to setting these classes up, use the `Ruby::Marshal.mapping` helper macro
class User
property :id, :name
ruby_marshal_properties({ id: ::Int32, name: ::String })
Ruby::Marshal.mapping({ id: ::Int32, name: ::String })
end
```

Expand Down
2 changes: 1 addition & 1 deletion spec/data/generate-marshalled-objects.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class UserHash < Hash ; end
File.open( File.join(File.dirname( __FILE__ ), 'marshalled-string.out'), 'w') { |f| f.write(Marshal.dump("test_string")) }
File.open( File.join(File.dirname( __FILE__ ), 'marshalled-symbol.out'), 'w') { |f| f.write(Marshal.dump(:test_symbol)) }
File.open( File.join(File.dirname( __FILE__ ), 'marshalled-symbol-array.out'), 'w') { |f| f.write(Marshal.dump([:hello, :hello])) }
File.open( File.join(File.dirname( __FILE__ ), 'marshalled-complex-array.out'), 'w') { |f| f.write(Marshal.dump([:hello, :hello, [:hello, :test, 1, nil],1_000_000, true, false, nil, "string", "string"])) }
File.open( File.join(File.dirname( __FILE__ ), 'marshalled-complex-array.out'), 'w') { |f| f.write(Marshal.dump([:hello, :hello, [:hello, :test, 1, nil],1_000_000, true, false, nil, "string", "string", -1.2])) }
File.open( File.join(File.dirname( __FILE__ ), 'marshalled-hash.out'), 'w') { |f| f.write(Marshal.dump({:simple => 'hash'})) }
hash_with_default = Hash.new("default_value")
hash_with_default['key'] = 1
Expand Down
Binary file modified spec/data/marshalled-complex-array.out
Binary file not shown.
250 changes: 250 additions & 0 deletions spec/ruby_marshal_dump_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
require "./spec_helper"

describe Ruby::Marshal do

it "#dump true" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-true.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(true) ) }
object = Ruby::Marshal.dump(true)
Ruby::Marshal.load( File.open(f) ).data.should be_true
end

it "#dump false" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-false.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(false) ) }
object = Ruby::Marshal.dump(false)
Ruby::Marshal.load( File.open(f) ).data.should be_false
end

it "#dump nil" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-nil.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(nil) ) }
object = Ruby::Marshal.dump(nil)
Ruby::Marshal.load( File.open(f) ).data.should be_nil
end

it "#dump a class" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-class.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(User) ) }
object = Ruby::Marshal.dump(User)
Ruby::Marshal.load( File.open(f) ).data.should eq("User")
end

it "#dump a module" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-module.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(TestModule) ) }
object = Ruby::Marshal.dump(TestModule)
Ruby::Marshal.load( File.open(f) ).data.should eq("TestModule")
end

it "#dump a symbol" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-symbol.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(:test_symbol) ) }
object = Ruby::Marshal.dump(:test_symbol)
Ruby::Marshal.load( File.open(f) ).data.should eq("test_symbol")
end

it "#dump 0" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(0) ) }
object = Ruby::Marshal.dump(0)
Ruby::Marshal.load( File.open(f) ).data.should eq(0)
end

it "#dump 122" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero-byte-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(122) ) }
object = Ruby::Marshal.dump(122)
Ruby::Marshal.load( File.open(f) ).data.should eq(122)
end

it "#dump -122" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-zero-byte-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-122) ) }
object = Ruby::Marshal.dump(-122)
Ruby::Marshal.load( File.open(f) ).data.should eq(-122)
end

it "#dump -123" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-negative-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-123) ) }
object = Ruby::Marshal.dump(-123)
Ruby::Marshal.load( File.open(f) ).data.should eq(-123)
end

it "#dump 123" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-positive-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(123) ) }
object = Ruby::Marshal.dump(123)
Ruby::Marshal.load( File.open(f) ).data.should eq(123)
end

it "#dump 255" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-positive-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(255) ) }
object = Ruby::Marshal.dump(255)
Ruby::Marshal.load( File.open(f) ).data.should eq(255)
end

it "#dump -256" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-one-byte-negative-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-256) ) }
object = Ruby::Marshal.dump(-256)
Ruby::Marshal.load( File.open(f) ).data.should eq(-256)
end

it "#dump 256" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-positive-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(256) ) }
object = Ruby::Marshal.dump(256)
Ruby::Marshal.load( File.open(f) ).data.should eq(256)
end

it "#dump -257" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-negative-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-257) ) }
object = Ruby::Marshal.dump(-257)
Ruby::Marshal.load( File.open(f) ).data.should eq(-257)
end

it "#dump 65_535" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-positive-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(65_535) ) }
object = Ruby::Marshal.dump(65_535)
Ruby::Marshal.load( File.open(f) ).data.should eq(65_535)
end

it "#dump -65_536" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-two-byte-negative-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-65_536) ) }
object = Ruby::Marshal.dump(-65_536)
Ruby::Marshal.load( File.open(f) ).data.should eq(-65_536)
end

it "#dump 65_536" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-positive-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(65_536) ) }
object = Ruby::Marshal.dump(65_536)
Ruby::Marshal.load( File.open(f) ).data.should eq(65_536)
end

it "#dump 16_777_215" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-positive-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(16_777_215) ) }
object = Ruby::Marshal.dump(16_777_215)
Ruby::Marshal.load( File.open(f) ).data.should eq(16_777_215)
end

it "#dump -65_537" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-negative-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-65_537) ) }
object = Ruby::Marshal.dump(-65_537)
Ruby::Marshal.load( File.open(f) ).data.should eq(-65_537)
end

it "#dump -16_777_216" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-three-byte-negative-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-16_777_216) ) }
object = Ruby::Marshal.dump(-16_777_216)
Ruby::Marshal.load( File.open(f) ).data.should eq(-16_777_216)
end

it "#dump 16_777_216" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-positive-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(16_777_216) ) }
object = Ruby::Marshal.dump(16_777_216)
Ruby::Marshal.load( File.open(f) ).data.should eq(16_777_216)
end

it "#dump 1_073_741_823" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-positive-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(1_073_741_823) ) }
object = Ruby::Marshal.dump(1_073_741_823)
Ruby::Marshal.load( File.open(f) ).data.should eq(1_073_741_823)
end

it "#dump -16_777_217" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-negative-int-upper.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-16_777_217) ) }
object = Ruby::Marshal.dump(-16_777_217)
Ruby::Marshal.load( File.open(f) ).data.should eq(-16_777_217)
end

it "#dump -1_073_741_824" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-four-byte-negative-int-lower.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-1_073_741_824) ) }
object = Ruby::Marshal.dump(-1_073_741_824)
Ruby::Marshal.load( File.open(f) ).data.should eq(-1_073_741_824)
end

it "#dump -1.26479" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-float.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(-1.26479) ) }
object = Ruby::Marshal.dump(-1.26479)
Ruby::Marshal.load( File.open(f) ).data.should eq(-1.26479)
end

it "#dump an array" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-array.out")
a = ["string", 1, -1.2, nil, true, false, [true, nil, :symbol]]
b = ["string", 1, -1.2, nil, true, false, [true, nil, "symbol"]]
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) }
object = Ruby::Marshal.dump(a)
Ruby::Marshal.load( File.open(f) ).data.should eq(b)
end

it "#dump a hash" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-hash.out")
a = { "simple" => 1, :hash => -1.2 }
b = { "simple" => 1, "hash" => -1.2 }
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) }
object = Ruby::Marshal.dump(a)
Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::Hash).data.should eq(b)
end

it "#dump a hash with default value" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-hash-with-default.out")
a = Hash(String, String | Int32).new("Default")
a["simple"] = 1
#puts a["nonexistent"]
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) }
#puts `xxd #{f}`
object = Ruby::Marshal.dump(a)
r = Ruby::Marshal.load( File.open(f) ).as(Ruby::Marshal::HashWithDefault).data
r.should eq(a)
r["nada"].should eq("Default")
end

it "#dump an instance" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-instance-object.out")
object = DumpTestUser.new
object.id = 1
object.name = "string name"
object.valid = false
#object.opts = { "this" => "hash" }
write = Ruby::Marshal.dump(object)
File.open(f, "w") { |f| f.write(write) }
#result = Ruby::Marshal.load( DumpTestUser, File.open(f) )
#puts result.inspect
#result.should eq(object)
end

# TODO - these should dump InstanceObjects
it "#dump an regex" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-regex.out")
a = /[A-Za-z0-9]+/
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump(a) ) }
object = Ruby::Marshal.dump(a)
result = Ruby::Marshal.load( File.open(f) )
#puts result.inspect
result.data.should eq(a)
end

it "#dump \"a string\"" do
f = File.join(File.dirname( __FILE__ ), "tmp", "marshalled-string.out")
File.open(f, "w") { |f| f.write( Ruby::Marshal.dump("a string") ) }
object = Ruby::Marshal.dump("a string")
Ruby::Marshal.load( File.open(f) ).data.should eq("a string")
end

end
27 changes: 12 additions & 15 deletions spec/ruby-marshal_spec.cr → spec/ruby_marshal_load_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ describe Ruby::Marshal do
#puts `xxd #{SPEC_ROOT}/data/marshalled-complex-array.out`
object = Ruby::Marshal.load( File.read( "#{SPEC_ROOT}/data/marshalled-complex-array.out" ) )
object.should be_a(Ruby::Marshal::Array)
object.data.should eq(["hello", "hello", ["hello", "test", 1, nil], 1_000_000, true, false, nil, "string", "string"])
object.data.should eq(["hello", "hello", ["hello", "test", 1, nil], 1_000_000, true, false, nil, "string", "string", -1.2])
end

it "should read a marshalled string" do
Expand All @@ -209,12 +209,12 @@ describe Ruby::Marshal do
object.read_attr("id", true).should eq(1)
object.read_attr("name", true).should eq("Test")
object.read_attr("valid", true).should eq(true)
data_hash = object.read_attr("data").as(Ruby::Marshal::Hash)
data_hash["some"].data.should eq(true)
data_hash[1].data.should eq("extra")
data_hash.data.each do |(k, v)|
if(k.class == Ruby::Marshal::Hash)
v.data.should eq(0x01)
data_hash = object.read_attr("data").as(Hash)
data_hash["some"].should eq(true)
data_hash[1].should eq("extra")
data_hash.each do |(k, v)|
if(k.class == Hash)
v.should eq(0x01)
end
end
end
Expand All @@ -238,16 +238,14 @@ describe Ruby::Marshal do
it "should read a marshalled hash" do
#puts `xxd #{SPEC_ROOT}/data/marshalled-hash.out`
object = Ruby::Marshal.load( File.read( "#{SPEC_ROOT}/data/marshalled-hash.out" ) )
object.as(::Ruby::Marshal::Hash)["simple"].data.should eq("hash")
object.as(::Ruby::Marshal::Hash)["simple"].should eq("hash")
end

it "should read a marshalled hash with a default" do
#puts `xxd #{SPEC_ROOT}/data/marshalled-hash-with-default.out`
object = Ruby::Marshal.load( File.read( "#{SPEC_ROOT}/data/marshalled-hash-with-default.out" ) ).as(Ruby::Marshal::Hash)
object["key"].data.should eq(1)
object.default_value.data.should eq("default_value")
raw_hash = object.raw_hash
raw_hash["new_key"].should eq("default_value")
object["key"].should eq(1)
object.default_value.should eq("default_value")
end

it "should read a marshalled class" do
Expand Down Expand Up @@ -295,9 +293,8 @@ describe Ruby::Marshal do
object.should be_a(Ruby::Marshal::UserClass)
object = object.as(Ruby::Marshal::UserClass)
object.class_name.data.should eq("UserHash")
object.data.should be_a(Ruby::Marshal::HashWithDefault)
wrapped_object = object.data.as(Ruby::Marshal::HashWithDefault)
wrapped_object["data"].data.should eq(123)
wrapped_object = object.data.as(Hash)
wrapped_object["data"].should eq(123)
end

end
Loading