Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stamp function accept refs #96

Merged
merged 10 commits into from Jun 11, 2015
Merged

Stamp function accept refs #96

merged 10 commits into from Jun 11, 2015

Conversation

koresar
Copy link
Member

@koresar koresar commented Jun 9, 2015

@ericelliott @troutowicz @unstoppablecarl Please, review.

The main change is the object instantiation. See function Factory().

Now all the references mixed into an object instance as is was before. But then the props are safely merged into the instance. "Safely" means that no refs data will be overriden, but props will be merged to the existing properties where possible. See the unit test of this PR.

In my opinion this is the very best approach for all existing user cases I have ever met so far.

@@ -464,7 +468,8 @@ MyStamp.create().originalStamp === MyStamp; // true

### stamp.props() ###

Take n objects and deep merge them to the properties. Creates new stamp.
Take n objects and deep merge them safely to the properties. Creates new stamp.
Note: the merge algorythm will not change any existing `refs` data of a resulting object instance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

algorithm

@koresar
Copy link
Member Author

koresar commented Jun 9, 2015

Fixed comments above. Thanks guys!

@unstoppablecarl
Copy link
Contributor

I don't think ignoring existing properties is a good idea.

  • It breaks backward compatibility
  • does not follow our consistent 'last in' behavior
  • I think most would be surprised to find properties ignored when creating an object instance with a stamp.

We need a name for this arg. It should be referred to as settings (or something else) to avoid confusing it with props, it is difficult to talk about it and compare it to props if it is also called props.

I am starting to question if the settings in var instance = myStamp(settings) should be merged at all. It may be making too many assumptions about usage. I would rather see it passed to the init functions and let the developer decide how it is used. init({ args: args, instance: instance, stamp: factory, settings: settings } (where settings is the refs arg above). I don't think we can make the same assumptions of purpose or intent with settings as we can with refs, init, props, and static.

I realize this would be a serious breaking change to backward compatibility and therefore probably not wise but I wanted to see what others thought. Would this make sense if backward compatibility were not an issue ?

I would like to see a way to circumvent the settings merge behavior. I have some ideas I will put in a PR.

@koresar
Copy link
Member Author

koresar commented Jun 9, 2015

I don't think ignoring existing properties is a good idea.

What "ignoring" are you referring to? The code does not ignore anything.

@koresar
Copy link
Member Author

koresar commented Jun 9, 2015

@unstoppablecarl #50 might give you some insight maybe.

@unstoppablecarl
Copy link
Contributor

"Safely" means that no refs data will be overridden, but props will be merged to the existing properties where possible

I assume this means properties matching refs will be ignored?

@unstoppablecarl
Copy link
Contributor

We discusses this here and agreed that the settings object should be shallow merged #57

#57 (comment)

@koresar
Copy link
Member Author

koresar commented Jun 9, 2015

Please, do not use any new terminology to replace the existing. What do you mean by settings?

@unstoppablecarl
Copy link
Contributor

var instance = myStamp(settings) what should I call it to differentiate from props?

@koresar
Copy link
Member Author

koresar commented Jun 9, 2015

These are refs. Please, check the code - the variable name reflects the usage.
Also check the changes to the README. It also says refs or references literally everywhere.

@koresar
Copy link
Member Author

koresar commented Jun 9, 2015

I assume this means properties matching refs will be ignored?

Nope, they will be not. "props" will be merged into an instantiated object which already has all the refs mixed in. Pseudo code:

var instance = Object.create(...);
_.mixin(instance, refs);
_.merge(instance, props);

@unstoppablecarl
Copy link
Contributor

I didn't completely understand the intended behavior. I get it now that I did some testing.

This is the only strange behavior I found but I think it is acceptable given the way js works.

var stamp = stampit().props({
    connection: 'my connection',
});

var instance = stamp({connection: undefined});
console.log(instance); // { connection: 'my connection' }

@koresar
Copy link
Member Author

koresar commented Jun 11, 2015

I'll merge this tomorrow if no objections.

t.equal(o2.deep.bar, 'bar');
t.equal(o2.deep.baz, 'baz');
t.equal(o1.shallow1, 'leave me as is', 'A conflicting shallow reference must not be touched by props');
t.equal(o1.shallow2, 'merge me!', 'A non conflicting shallow reference must be merged form props');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo? Should be "merged from props."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 fixed

@koresar
Copy link
Member Author

koresar commented Jun 11, 2015

@unstoppablecarl The strange behavior you found can be easily fixed.

Your code:

var stamp = stampit().props({
    connection: 'my connection',
});

var instance = stamp({connection: undefined});
console.log(instance); // { connection: 'my connection' }

Replacing undefined with null fixes it:

var stamp = stampit().props({
    connection: 'my connection',
});

var instance = stamp({connection: null});
console.log(instance); // { connection: null }

@koresar
Copy link
Member Author

koresar commented Jun 11, 2015

Since Eric has done his part I'm merging this in.

@ericelliott, please publish to NPM.

Meanwhile, I'll work on the Advanced Examples.

koresar added a commit that referenced this pull request Jun 11, 2015
@koresar koresar merged commit 406afa4 into master Jun 11, 2015
@ericelliott
Copy link
Contributor

var stamp = stampit().props({
    connection: 'my connection',
});

var instance = stamp({connection: undefined});
console.log(instance); // { connection: 'my connection' }

That is a confusing example. Normally you only want to override a property if the property is set in the override object. By passing in undefined, you're explicitly stating that the property is not set, so if there is a default value, as is the case here, then the default value should be used, which is exactly what happens.

As @koresar pointed out, if you want to override it with a null value, you should pass null instead of undefined. If you want to unset the key entirely, use an .init() function and the delete keyword, or compose from a stamp that doesn't contain the unwanted key in the first place. ;)

@unstoppablecarl
Copy link
Contributor

I understand all of that. As I said before I think it is acceptable given the way js works.

@ericelliott
Copy link
Contributor

:)

@koresar koresar deleted the stamp-function-accept-refs branch June 13, 2015 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants