Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/db2f4b0954fdf1680c9abbf21f85d4d5 to your computer and use it in GitHub Desktop.
Save JoshCheek/db2f4b0954fdf1680c9abbf21f85d4d5 to your computer and use it in GitHub Desktop.
Classes to / from JSON with inheritance and such (https://twitter.com/postmodern_mod3/status/1348330707420991497)
# A potential way to deal with https://twitter.com/postmodern_mod3/status/1348330707420991497
# include it to get reasonable JSONability
module JsonCreatable
def self.append_features(base)
base.extend ClassMethods
base.include InstanceMethods
end
module ClassMethods
def json_create(hash)
new **hash.transform_keys(&:intern)
end
end
module InstanceMethods
def initialize(*rest, json_class: nil, **kwrest, &block)
super *rest, **kwrest, &block
end
def as_json
hash = defined?(super) ? super : {}
{ **hash, json_class: self.class.name }
end
end
end
# Parent class
class User
include JsonCreatable
attr_reader :name
def initialize(name:, **kwrest, &block)
super **kwrest, &block
@name = name
end
def as_json
{ **super, name: name }
end
end
# Child class
module Admin
class User < ::User
def initialize(is_admin:, **kwrest, &block)
super **kwrest, &block
@is_admin = is_admin
end
def admin?
@is_admin
end
def as_json
{ **super, is_admin: admin? }
end
end
end
require 'json'
users = JSON.parse(<<~JSON, create_additions: true)
[ {"json_class":"User", "name":"Josh"},
{"json_class":"Admin::User", "name":"Marissa", "is_admin":true},
{"json_class":"Admin::User", "name":"Dave", "is_admin":false}
]
JSON
users
# => [#<User:0x00007ffaa79f4260 @name="Josh">,
# #<Admin::User:0x00007ffaa79efda0 @is_admin=true, @name="Marissa">,
# #<Admin::User:0x00007ffaa79ef968 @is_admin=false, @name="Dave">]
users.map(&:as_json)
# => [{:json_class=>"User", :name=>"Josh"},
# {:json_class=>"Admin::User", :name=>"Marissa", :is_admin=>true},
# {:json_class=>"Admin::User", :name=>"Dave", :is_admin=>false}]
users.map &:name # => ["Josh", "Marissa", "Dave"]
users.grep(Admin::User).map(&:admin?) # => [true, false]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment