-
Notifications
You must be signed in to change notification settings - Fork 57
gorillib model additional_notes
This is a scratch pad used during the design process. Don't trust anything that's below, or worry about it making sense.
- for unset attributes, could return UnsetNull (descendent of NullObject)
ICSS:
-
If a class explicitly inherits from an ICSS class
Geo::Whatever < Geo::Place
, does the new class have a new schema? I think so -
can you assign nil to a required field?
These are types:
ruby type kind avro type json type example
---------- -------- --------- --------- ---------
NilClass simple null null nil
Boolean simple boolean boolean true
Integer simple int,long integer 1
Float simple float,double number 1.1
String simple bytes string "\u00FF"
String simple string string "foo"
Time simple time string "2011-01-02T03:04:05Z"
RecordType named record object {"a": 1}
Enum named enum string "FOO"
Array container array array [1]
Hash container map object { "a": 1 }
String container fixed string "\u00ff"
XxxFactory union union object
-
method on class
-
separate factory set
-
want a reasonable and non-magical default
-
want to be able to override sensibly
-
nil
for string isnil
vsnil
for string is''
- boolean from
0
is false vs true
-
-
.receive
calls new with all given args, returns obj.-
question:
create
? - has to go through
initialize
: required and default declarations get fucked up if you create an object without giving it a base set of attributes
-
question:
-
model initializer
- calls
#update
,super
- calls
-
.receivable?
: responds to#attributes
or to (#each_pair
andhas_key?
). -
coerce
: prepares a type-coerced attribute hash: for each field, callsfield.coerce
if the source value exists (using indifferent access), -
instance
#receive!
- for each field, calls
#receive_{foo}
if the source value exists (using indifferent access) - accepts anything
receivable?
- (we must either use UnsetNull or add a
#existing_attributes
or something) - does not matter if the source object has a method named for the field.
-
question: is
rcvr_remaining
callback always received? -
question:
after_receive
-- defined directly? or use callbacks?
- for each field, calls
-
#receive_foo(val)
- gets the received instance by calling
.receive
on the field's type - question ... or should it call a method on the field
- calls
write_attribute
- gets the received instance by calling
alternative:
-
.receive
- first arg must be a
receivable?
object -
coerce
the receivable into an initializer-ready attribute hash - calls
initialize
with that attribute hash and any other args
- first arg must be a
-
#receive!
The question largely revolves around gating. What are the touchpoints?
-
update
/merge
-
receive
/receive!
-
initialize
-
at what point do we need the context of the object to be around
- insists that typecasting happen in isolation of object, which seems fair.
http://objectsonrails.com/#sec-5-2
setter injection to strategize how Blog objects create new entries:
class Blog
# ...
attr_writer :post_factory
# ...
private
def post_factory
@post_factory ||= Post.public_method(:new)
end
end
#public_method, if you're unfamiliar with it, instantiates a call-able Method object. When the object's #call method is invoked it will be as if we called the named method on the original object. The "public" in the name refers to the fact that unlike #method, #public_method respects public/private boundaries and will not generate a Method object for a private method.
question: defaults are either
- late-resolved: read_attribute falls through to the field.default if unset. An attribute is unset until it is explicitly written, even if it has a default.
- late-resolved, persistent: read_attribute falls through to the field.default if unset; value is then set on the attribute. Yuck.
- callback-resolved: attribute is set to its field's default value in a callback (maybe
after_receive
).- A field with a default may not be
unset
.
- A field with a default may not be
The Layer feature allows late-resolved values, so I lean towards callback-resolved. The question there is what lifecycle event triggers default setting:
-
initialize
-- means we have to chain the initializer.- if a value is unset
-
update
-- yuck -
receive!
-- means you can have an object that has been initialized but no defaults. However, you do get
I think the super
method of initialize should set the default values. They will be clobbered in any further receive call.
Setting default values Defaults can be set via the :default key for a property. They can be static values, such as 12 or "Hello", but DataMapper also offers the ability to use a Proc to set the default value. The property becomes whatever the Proc returns, which will be called the first time the property is used without having first set a value. The Proc itself receives two arguments: The resource the property is being set on, and the property itself.
These are schemata:
ruby type example
---------- -----------------------------------------
NamedSchema [parent class for schema]
PrimitiveSchema { type:"string" }
RecordSchema { type:"record", name:"", fields:[...] }
EnumSchema
ArraySchema
HashSchema
FixedSchema
UnionSchema
a type:
-
is represented as a ruby class
- so the class is
< RecordType
and instances areis_a?(RecordType)
- so the class is
a schema
- a class
is_a?(RecordSchema)
a record type (eg Geo::Place
):
- is a class
-
extend RecordSchema
, giving the class itself-
field
: define a new field -
fields
,field_names
: enumerate fields and fromNamedSchema
, metamodel
-
schema
: a class inheritable
-
-
include RecordType
, giving its instances-
attributes
: map from field names to values -
read_attribute
,write_attribute
,unset_attribute
, andattribute_set?
-
==
: two records are equal if they have the same class and same attributes
-
-
include Meta::Geo::PlaceType
-
{foo}
,{foo}=
: callread_attribute
andwrite_attribute
resp. -
receive_foo
: type converts, then callswrite_attribute
-
Nominate field to be serialized as reference