Project

ruson

0.01
The project is in a healthy, maintained state
A Ruby serialization/deserialization library to convert Ruby Objects into JSON and back
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
 Project Readme

Ruson

A Ruby serialization/deserialization library to convert Ruby Objects into JSON and back

Installation

Add this line to your application's Gemfile:

gem 'ruson'

And then execute:

$ bundle

Or install it yourself as:

$ gem install ruson

Usage

Basic

post.json

{
  "title": "Ruson",
  "content": "Welcome!"
}
require 'ruson'

class Post < Ruson::Base  
  field :title
  field :content
end

json = File.read('post.json')
post = Post.new(json)
post.title #=> 'Ruson'
post.content #=> 'Welcome!'

name

post.json

{
  "title": "Ruson",
  "post_url": "http://sample.com"
}
require 'ruson'

class Post < Ruson::Base
  field :title
  field :url, name: 'post_url'
end

json = File.read('post.json')
post = Post.new(json)
post.url #=> 'http://sample.com'

nilable

post.json

{
  "title": "Ruson",
  "post_url": "http://sample.com"
}
class Post < Ruson::Base
  field :title, nilable: false
  field :url, name: 'post_url'
end

json = File.read('post.json')
post = Post.new(json) #=> Ruson::NotNilException

nested class

class

post.json

{
  "title": "Ruson",
  "post_url": "http://sample.com",
  "picture": {
    "title": "nice picture",
    "url": "http://sample.com/picture.png"
  }
}
require 'ruson'

class Post < Ruson::Base
  field :title
  field :picture, class: Picture
end

class Picture < Ruson::Base
  field :title
  field :url
end

json = File.read('post.json')
post = Post.new(json)
post.picture.url #=> 'http://sample.com/picture.png'
Primary classes
  • Ruson::Array
  • Ruson::Boolean
  • Ruson::Float
  • Ruson::Integer
  • Ruson::Time

post.json

{
  "title": "Ruson",
  "items": ["orange", "apple"],
  "is_new": "true",
  "rate": "3.8",
  "view": "1234",
  "expired_at": 1575608299
}
class Post < Ruson::Base
  field :title
  field :items, class: Ruson::Array
  field :is_new, class: Ruson::Boolean
  field :rate, class: Ruson::Float
  field :view, class: Ruson::Integer
  field :expired_at, class: Ruson::Time
end

json = File.read('post.json')
post = Post.new(json)
post.items #=> ["orange", "apple"]
post.is_new #=> true
post.rate #=> 3.8
post.view #=> 1234
post.expired_at #=> 2019-12-06 04:58:19 +0000
each class

post.json

{
  "title": "Ruson",
  "tags": [
    {
      "name": "Ruby"
    },
    {
      "name": "Json"
    }
   ]
}
require 'ruson'

class Post < Ruson::Base
  field :title
  field :tags, each_class: Tag
end

class Tag < Ruson::Base
  field :name
end

json = File.read('post.json')
post = Post.new(json)
post.tags.first.name #=> 'Ruby'

enum

article.json

{  
   "title":"Title",
   "status":"draft"
}
class Article < Ruson::Base
  field :title
  enum status: { :draft, :published }
end

article = Article.new('article.json')

article.status #=> :draft
article.draft? #=> true

article.status = 'published'
article.status #=> :published

article.status = 'undefined'
  #=> undefined is not a valid status (ArgumentError)

to_json

class Post < Ruson::Base
  field :title
  field :url
end

json = File.read('post.json')
post = Post.new(json)
post.url = 'https://example.com/examples'

post.to_json #=> "{\"title\":\"Ruson\",\"url\":\"https://example.com/examples\"}"

to_hash

class Post < Ruson::Base
  field :title
  field :url
end

json = File.read('post.json')
post = Post.new(json)
post.url = 'https://example.com/examples'

post.to_hash #=> {title: "Ruson", url: "https://example.com/examples" }

API json parser

class Article < Ruson::Base
  field :title
  field :description
end

conn = Faraday::Connection.new(url: 'https://your.api/articles/1') do |faraday|
  faraday.request :url_encoded
  faraday.adapter Faraday.default_adapter
end

response = conn.get
article = Article.new(response.body)
article.title

Persistence

Persistence will save the models as JSON file, with the model ID as filename, and model class name as parent folder so that a User model with ID 1 will be saved as Users/1.json.

You must define the output_folder before to be able to call save or destroy.

Ruson.output_folder = './db/'

Creating new record

class User < Ruson::Base
  field :first_name
  field :last_name
  field :email
  field :title
end

# Using new + save
guillaume = User.new(first_name: 'Guillaume', last_name: 'Briat', email: 'guillaume@kaamelott.fr')
guillaume.save # Creates the ./db/Users/1.json file

# Or using the create method
guillaume = User.create(first_name: 'Guillaume', last_name: 'Briat', email: 'guillaume@kaamelott.fr')

puts File.read('./db/Users/1.json')
{"first_name":"Guillaume","last_name":"Briat","email":"guillaume@kaamelott.fr"}
=> nil

Updating a record

# Assigning a value + save
guillaume.title = 'Burgundians King'
guillaume.save # Updates the ./db/Users/1.json file

# Or using the update method
guillaume.update(title: 'Burgundians King')

puts File.read('./db/Users/1.json')
{"first_name":"Guillaume","last_name":"Briat","email":"guillaume@kaamelott.fr","title":"Burgundians King"}
=> nil

Destroying a record

guillaume.destroy # Deletes the ./db/Users/1.json file

puts File.read('./db/Users/1.json')
Traceback (most recent call last):
       16: from /usr/local/bundle/gems/bundler-2.0.2/exe/bundle:30:in `block in <top (required)>'
       ...
        2: from (irb):26
        1: from (irb):26:in `read'
Errno::ENOENT (No such file or directory @ rb_sysopen - ./db/Users/1.json)

Querying

Ruson allows you to query for existing records.

You must define the output_folder before to query records.

Ruson.output_folder = './db/'

Find a record by ID

User.find(1) # Searches for a ./db/Users/1.json file

# Searching a user which doesn't exist
User.find(1234) #=> nil
User.find!(1234) #=> raises Ruson::RecordNotFound

Find first record

User.first # Loads the first ./db/Users/*.json file.

# Without existing User records
User.first #=> nil
User.first! #=> raises Ruson::RecordNotFound

Find a record by attributes

post.json

{
  "title": "Ruson",
  "content": "Welcome!"
}
Post.create(File.read('post.json'))
Post.where(title: 'Ruson')
#=> [#<Post:0x000055bb2e907b78 @title="Ruson", @content="Welcome!", @id=1>]

Post.where(content: 'Wel')
#=> []

Post.where(content: 'Welcome!')
#=> [#<Post:0x000055bb2e907b78 @title="Ruson", @content="Welcome!", @id=1>]

Post.where(title: 'Ruson', content: 'Welcome!')
#=> [#<Post:0x000055bb2e907b78 @title="Ruson", @content="Welcome!", @id=1>]

Development

Without Docker

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

With Docker

$ docker build -t `whoami`/ruson .

In order to see the available Rake tasks:

$ docker --rm `whoami`/ruson
rake build            # Build ruson-1.2.0.gem into the pkg directory
rake clean            # Remove any temporary products
rake clobber          # Remove any generated files
rake install          # Build and install ruson-1.2.0.gem into system gems
rake install:local    # Build and install ruson-1.2.0.gem into system gems without network access
rake release[remote]  # Create tag v1.2.0 and build and push ruson-1.2.0.gem to rubygems.org
rake spec             # Run RSpec code examples

--rm means delete the container after the command has ended.

In order to execute the tests:

$ docker run --rm -it --volume "$PWD":/gem/ `whoami`/ruson rake spec

--volume is used to sync the files from your current folder into the container so that if you change a file, the modification is available in the container.

In the case you'd like to access the IRB console:

$ docker run --rm -it --volume "$PWD":/gem/ `whoami`/ruson irb
irb(main):001:0> require 'ruson'
=> true
irb(main):002:0>

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/klriutsa/ruson. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Code Status

Build Status

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Ruson project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.