Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/gaynetdinov/ex_marshal
Ruby Marshal format implemented in Elixir
https://github.com/gaynetdinov/ex_marshal
elixir marshal ruby
Last synced: 26 days ago
JSON representation
Ruby Marshal format implemented in Elixir
- Host: GitHub
- URL: https://github.com/gaynetdinov/ex_marshal
- Owner: gaynetdinov
- License: isc
- Created: 2015-11-05T22:08:33.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2022-07-28T17:11:21.000Z (over 2 years ago)
- Last Synced: 2024-05-02T10:18:28.317Z (7 months ago)
- Topics: elixir, marshal, ruby
- Language: Elixir
- Homepage:
- Size: 176 KB
- Stars: 39
- Watchers: 2
- Forks: 13
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- freaking_awesome_elixir - Elixir - Ruby Marshal format implemented in Elixir. (Protocols)
- fucking-awesome-elixir - ex_marshal - Ruby Marshal format implemented in Elixir. (Protocols)
- awesome-elixir - ex_marshal - Ruby Marshal format implemented in Elixir. (Protocols)
README
# ExMarshal [![Build Status](https://travis-ci.org/gaynetdinov/ex_marshal.svg?branch=master)](https://travis-ci.org/gaynetdinov/ex_marshal) [![Hex pm](http://img.shields.io/hexpm/v/ex_marshal.svg?style=flat)](https://hex.pm/packages/ex_marshal)
`ExMarshal` encodes and decodes Elixir terms according to [Ruby Marshal](http://docs.ruby-lang.org/en/2.2.0/marshal_rdoc.html) format.
Currently supported Ruby types are `nil`, `false`, `true`, `Fixnum`, `Bignum`, `BigDecimal`, `Float`, `Symbol`, `String`, `Array`, `Hash` as well as user-defined types such as `Date`.
## Why?
Once you decide to integrate small Elixir tool into big-old-legacy Ruby system, chances are that you need to interact with [Memcached](http://memcached.org). As soon as Ruby code writes something into Memcached, most likely Ruby uses [dalli](https://github.com/mperham/dalli) gem. And `Dalli` uses [Ruby Marshal](http://docs.ruby-lang.org/en/2.2.0/marshal_rdoc.html) by default.
Another use case is to decode Rails session encoded using Ruby Marshal. For this you can use [plug_rails_cookie_session_store](https://github.com/cconstantin/plug_rails_cookie_session_store) or [plug_session_redis](https://github.com/aposto/plug_session_redis#custom-serializers) if you want to store session data in Redis.
## Installation
Add ExMarshal as a dependency to your `mix.exs` file:
```elixir
def deps do
[{:ex_marshal, "0.0.13"}]
end
```## Usage
```elixir
iex(1)> ExMarshal.decode(<<4, 8, 91, 8, 105, 6, 105, 7, 105, 8>>)
[1, 2, 3]
iex(2)> ExMarshal.encode([1, 2, 3])
<<4, 8, 91, 8, 105, 6, 105, 7, 105, 8>>
iex(3)>
```It is also possible to decode user objects such as Ruby dates using custom parsers which can be specified via the `user_object_parsers` option:
```elixir
iex(1)> value = <<4, 8, 85, 58, 9, 68, 97, 116, 101, 91, 11, 105, 0, 105, 3, 72, 136, 37, 105, 0, 105, 0, 105, 0, 102, 12, 50, 50, 57, 57, 49, 54, 49>>
<<4, 8, 85, 58, 9, 68, 97, 116, 101, 91, 11, 105, 0, 105, 3, 72, 136, 37, 105,
0, 105, 0, 105, 0, 102, 12, 50, 50, 57, 57, 49, 54, 49>>
iex(2)> ExMarshal.decode(value, user_object_parsers: %{Date: fn [_, julian_day, _, _, _, _] -> Date.from_gregorian_days(julian_day - 1721425) end})
~D[2021-05-20]
```## Nullify Ruby Objects
The default behaviour of ExMarshal is to raise an error when trying to decode an serilized ruby object. This config option can be used to nullify the ruby object without raising an error:
```elixir
config :ex_marshal,
nullify_objects: true
```__Use Case__ Rails 3.2 puts Ruby Objects into session(i.e. Flash messages wrapped in an object). When Phoenix is trying to read Rails session, this will cause ExMarshal to raise an error and a 500 error in Phoenix. If you don't need to read these values from Elixir/Phoenix, this option allows ExMarshal to skip objects.
## ExMarshal with Memcache.Client
One of the reasons why `ExMarshal` was created is to work with `Memcached`. Here is how `ExMarshal` can be used with [Memcache.Client](https://github.com/tsharju/memcache_client):
```elixir
defmodule Memcache.Client.Transcoder.Ruby do
@behaviour Memcache.Client.Transcoder@ruby_type_flag 0x0001
def encode_value(value) do
{ExMarshal.encode(value), @ruby_type_flag}
enddef decode_value(value, @ruby_type_flag) do
ExMarshal.decode(value)
enddef decode_value(_value, data_type) do
{:error, {:invalid_data_type, data_type}}
end
end
```Then tell `Memcache.Client` to use this transcoder:
```elixir
config :memcache_client,
transcoder: Memcache.Client.Transcoder.Ruby
```### Examples
#### Read
Ruby side
```ruby
:1 > dc = Dalli::Client.new('localhost:11211')
:2 > dc.set("str", "hello elixir")
=> true```
Elixir side
```elixir
iex(1)> Memcache.Client.get("str")
%Memcache.Client.Response{cas: 184, data_type: 1, extras: <<0, 0, 0, 1>>,
key: "", status: :ok, value: "hello elixir"}
```#### Write
Elixir side
```elixir
iex(1)> Memcache.Client.set("str", "hello ruby")
%Memcache.Client.Response{cas: 185, data_type: nil, extras: "", key: "",
status: :ok, value: ""}
```Ruby side
```ruby
:1 > dc = Dalli::Client.new('localhost:11211')
:2 > dc.get("str")
=> "hello ruby"
```## Kudos
Thanks to [@tsharju](https://github.com/tsharju) for ability to use custom transcoders in [Memcache.Client](https://github.com/tsharju/memcache_client)
Thanks to [@shepmaster](https://github.com/shepmaster) for [series](http://jakegoulding.com/blog/2013/01/15/a-little-dip-into-rubys-marshal-format/) [of](http://jakegoulding.com/blog/2013/01/16/another-dip-into-rubys-marshal-format/) [posts](http://jakegoulding.com/blog/2013/01/20/a-final-dip-into-rubys-marshal-format/) about Ruby Marshal format.
Special thanks to [@lexmag](https://github.com/lexmag) for help in writing this tool and for guiding me through Elixir world.
## License
This software is licensed under [the ISC license](LICENSE).