module EasyAttrs

  readers :id, :name
end

class BetterItem < Item
  accessors :price
end

$ BetterItem.new(id: 1, name: 'Better Item', price: 25)

> #<BetterItem:0x007faef0f2f930 @id=1, @name=“Better Item”, @price=25>

class EvenBetterItem < BetterItem
  readers :category
end

$ EvenBetterItem.new(id: 1, name: 'Better Item', price: 25, category: 'BOOOH')

> #<EvenBetterItem:0x007fbb10371978

  @category="BOOOH",
  @id=1,
  @name="Better Item",
  @price=25
>

Public Class Methods

included(klass) click to toggle source
# File lib/easy_attrs.rb, line 172
def self.included klass
  klass.extend ClassMethods
end
new(raw_input={}) click to toggle source

Transform all top level keys to snake case symbols to handle camel case input. Then, if a given key is part of `all_attributes` AND its content is a Hash, recursively transform all keys to snake case symbols. We want to avoid running `deep_transform_keys` on the raw_input because we may end up transforming a lot of deeply nested keys that will be discarded if they are not part of `all_attributes`.

It's fastest to pass a Hash as input. A Json string is slower. A Hash with camel case keys is even slower. And a Json string with camel case keys is the slowest.

# File lib/easy_attrs.rb, line 188
def initialize raw_input={}
  input = parse_input(raw_input)
  set_instance_variables(input) unless input.empty?
end

Private Instance Methods

parse_input(raw_input) click to toggle source
# File lib/easy_attrs.rb, line 195
def parse_input raw_input
  if raw_input.is_a?(Hash)
    raw_input
  elsif raw_input.is_a?(String)
    ActiveSupport::JSON.decode(raw_input)
  else
    {}
  end.map { |k, v| [k.to_s.underscore.to_sym, v] }.to_h
end
set_instance_variables(attrs_as_hash) click to toggle source
# File lib/easy_attrs.rb, line 205
def set_instance_variables attrs_as_hash
  self.class.all_attributes.each do |attribute|
    raw_value = attrs_as_hash[attribute.to_sym]
    next if raw_value.nil?

    value = if raw_value.is_a?(Hash)
      raw_value.deep_transform_keys { |k| k.to_s.underscore.to_sym }
    else
      raw_value
    end

    instance_variable_set("@#{attribute}", value)
  end
end