def property(name, *bool_options, **options)
      sym_name = name.to_sym
      @_lazer_metadata.add(sym_name, KeyMetadata.new(sym_name, *bool_options, **options))
      define_method(sym_name) { read_attribute(sym_name) }
    end
def property(name, *bool_options, **options)
      sym_name = name.to_sym
      @_lazer_metadata.add(sym_name, KeyMetadata.new(sym_name, *bool_options, **options))
      define_method(sym_name) { read_attribute(sym_name) }
    end
Define a property.
 @param name [Symbol] the name of the property method
 @param bool_options [Array<Symbol>] options that are set to true
 @param options [Hash] the options to create the property with
 @option options [Boolean] :required (false) whether existence of this property should be
   checked on model creation
 @option options [Boolean] :nil (false) shortcut for default: nil
 @option options [Object, Proc] :default the default value to return if not provided
 @option options [Symbol] :from (name) the key in the source object to get the property from
 @option options [Proc, Symbol, nil] :with an optional transformation to apply to the value
 @return [Symbol] the name of the created property

 @example
   class MyModel
     include LazyLazer

     property :id, :required
     property :timestamp, with: ->(i) { Time.at(i) }
     property :created_at, default: ->() { Time.now }
     property :camel_case, from: :camelCase
   end