Skip to content

Instantly share code, notes, and snippets.

@jessecurry
Last active December 17, 2015 18:55
Show Gist options
  • Save jessecurry/2809c2242719482d1940 to your computer and use it in GitHub Desktop.
Save jessecurry/2809c2242719482d1940 to your computer and use it in GitHub Desktop.
Wrap JSON data with type-safe methods
module JsonWrapper
class Base
MAPPING_TYPES = {
array: :to_a,
boolean: :to_bool,
date: :to_date,
datetime: :to_datetime,
float: :to_f,
hash: :to_h,
integer: :to_i,
string: :to_s
}.freeze
attr_reader :json_data
def initialize json_hash = {}
@json_data = json_hash
end
#
def self.map_json keypath, method_name, type = :string
define_method method_name do
value = instance_variable_get("@#{method_name.to_s}")
unless value.nil?
return value
else
begin
keys = keypath.split('.')
transformer = MAPPING_TYPES[type]
# grab the last part of the keypath
key = keys.pop
# Walk the first part of the keypath
data = @json_data
while keys.length > 0 do
data = data[(keys.shift).to_s].try(:to_h)
end
value = data[key.to_s].try(transformer)
if block_given?
value = yield(value)
end
instance_variable_set("@#{method_name.to_s}", value)
rescue StandardError => e
Rails.logger.error "[RevelApi::Base] #{e}"
return nil
end
end
end
end
end
end
{
"id": 10019348,
"name": {
"first": "Jesse",
"last": "Curry"
}
}
class Person < JsonWrapper::Base
map_json 'id', :id, :integer
map_json 'name.first', :first_name, :string
map_json 'name.last', :last_name, :string do |l|
l.try(:upcase)
end
end
# From: http://drawingablank.me/blog/ruby-boolean-typecasting.html
class String
def to_bool
return true if self == true || self =~ (/^(true|t|yes|y|1)$/i)
return false if self == false || self.blank? || self =~ (/^(false|f|no|n|0)$/i)
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
end
end
class Fixnum
def to_bool
return true if self == 1
return false if self == 0
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
end
end
class TrueClass
def to_i; 1; end
def to_bool; self; end
end
class FalseClass
def to_i; 0; end
def to_bool; self; end
end
class NilClass
def to_bool; false; end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment