Last active
December 30, 2023 21:13
-
-
Save micahboyd/55e42e49a66422d55f73277244fb5b17 to your computer and use it in GitHub Desktop.
JSON #parse object_class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Capture JSON into custom object similar to OpenStruct | |
class JsonClass | |
def []=(key, value) | |
instance_variable_set("@#{key}", new_member!(key, value)) | |
end | |
def [](key) | |
instance_variable_get("@#{key}") | |
end | |
def new_member!(key, value) | |
name = value.to_sym | |
unless singleton_class.method_defined?(name) | |
define_singleton_method(name) { instance_variable_get("@#{name}") } | |
define_singleton_method("#{name}=") { |v| instance_variable_set("@#{name}", v) } | |
end | |
value | |
end | |
end | |
json = '{"a":"a","b":"b"}' | |
parsed_json = JSON.parse(json, object_class: JsonClass) | |
# getting values | |
parsed_json[:a] # => 'a' | |
parsed_json.a # => 'a' | |
# updating values | |
parsed_json.b # => 'b' | |
parsed_json[:b] = 'b2' | |
parsed_json.b # => 'b2' | |
# setting new keys | |
parsed_json[:c] = 'c' | |
parsed_json.c # => 'c' | |
parsed_json.d = 'd' # => NoMethodError :/ | |
# Stricter object without setters or value mutations | |
class StrictJsonClass | |
def [](key) | |
return unless instance_variable_defined?("@#{key}") | |
send(key) | |
end | |
def members | |
instance_variables.map { |v| v.to_s.delete_prefix('@').to_sym } | |
end | |
def values | |
instance_variables.map { |v| instance_variable_get(v) } | |
end | |
def to_h | |
freeze_hash(members.zip(values).to_h) | |
end | |
alias attributes to_h | |
private | |
def []=(key, value) | |
defined = define_getter(key) | |
instance_variable_set("@#{key}", value) if defined | |
end | |
def define_getter(name) | |
return if singleton_class.method_defined?(name, false) | |
define_singleton_method(name) { instance_variable_get("@#{name}") } | |
end | |
def freeze_hash(hash) | |
hash.transform_values(&:freeze).freeze | |
end | |
end | |
json = '{"a":"1","b":"2"}' | |
strict_json = JSON.parse(json, object_class: StrictJsonClass) | |
# getting values | |
strict_json[:a] # => "1" | |
strict_json.a # => "1" | |
# getting attributes | |
strict_json.attributes # => {:a=>"1", :b=>"2"} | |
# can't modifiy attributes | |
strict_json.attributes[:b] = '3' # => FrozenError: frozen Hash | |
strict_json.attributes.merge!(c: '3') # => FrozenError: frozen Hash | |
strict_json.attributes[:b] << '3' # => FrozenError: frozen String | |
# can't update values | |
strict_json.b = '3' # => NoMethodError: undefined method | |
strict_json[:b] = '3' # => NoMethodError: private method | |
strict_json.b # => "2" | |
# can't set new keys | |
strict_json[:c] = '3' # => NoMethodError: private method | |
strict_json.c = '3' # => NoMethodError: undefined method | |
strict_json[:c] # => nil | |
strict_json.c # => NoMethodError: undefined method | |
# OpenStruct but able to handpick initialization data | |
class JsonStruct < OpenStruct | |
ATTRIBUTES = %w[a b] | |
def []=(key, value) | |
return unless ATTRIBUTES.include?(key) | |
super | |
end | |
end | |
json = '{"a":"1","c":"2"}' | |
json_struct = JSON.parse(json, object_class: JsonStruct) | |
# getting, setting values (all OpenStruct behaviour) | |
json_struct[:a] # => "1" | |
json_struct.a = '2' # => "2" | |
# only sets specifed attributes | |
json_struct.c # => nil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment