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

Global and deep stack context functions have wrong 'this' pointer. #117

Closed
wants to merge 6 commits into from
Closed

Conversation

wshaver
Copy link

@wshaver wshaver commented Aug 16, 2012

Related to: #96 (20 days previous to this post)

The fix in this pull request always uses the 'current context'

elem = elem.apply(context.current(), [this, context, null, {auto: auto, filters: filters}]);

The testing framework doesn't allow for more complicated contexts to be easily defined as it expects a simple single-stack context. Consider the following more complicated context and global stack:

var context = dust.makeBase({
 name: '1Bob',
 getName1: function(){ return this.name;}});
var instance = context.push({
 name: '2Joe',
 getName2: function(){ return this.name;}});
instance = instance.push({
 name: '3Tim',
 getName3: function(){ return this.name;}});

With the dust template:

{getName1}
{getName2}
{getName3}

The current implementation returns:
3Bob3Bob3Bob

Please indicate where and how to put a test with a more complicated context and I'll be happy to add one.

To solve this issue, we need to bind the function at compile time. Using underscore (just to get it done quickly) the code looks like this:

Context.prototype.get = function(key) {
  var ctx = this.stack, value;
  while(ctx) {
    if (ctx.isObject) {
      value = ctx.head[key];
      if(typeof value === 'function'){
        value = _.bind(value, ctx.head);
      }
      if (value !== undefined) {
        return value;
      }
    }
    ctx = ctx.tail;
  }
  if(this.global){
    value = this.global[key];
    if(typeof value === 'function'){
      value = _.bind(value, this.global);
    }
    return value;
  }
  return undefined;
};

This fixes the global / deep stack issue and passes the unit tests defined in pull request 96. I've implemented a minimal 'bind' inside of the .git function to avoid the use of underscore. Please tell me where to add tests for this issue. I've added some manual tests in a site I'm building, but would like to add tests in the linkedin project.

@travisbot
Copy link

This pull request passes (merged a69332c into d0affe6).

@vybs
Copy link
Contributor

vybs commented Aug 21, 2012

in the process of reviewing. thanks @wshaver

@wshaver
Copy link
Author

wshaver commented Aug 21, 2012

https://github.com/wshaver/speck This is some requirejs + dustjs + backbone glue I wrote. I turns the backbone view into the global context for the dustjs snippet, so that the snippets can call members of the view. (With this patch anyway.)

@ghost ghost assigned jimmyhchan and smfoote Sep 4, 2012
@vybs
Copy link
Contributor

vybs commented Sep 10, 2012

@wshaver Sorry for the delay, but overall + 1 on the idea and also thanks for bringing this up.

Are you still looking for pointers to add tests?

Adding a complex context is no different than here
https://github.com/linkedin/dustjs/blob/master/test/jasmine-test/spec/grammarTests.js

@wshaver
Copy link
Author

wshaver commented Sep 10, 2012

Is this the file I should add tests to for this issue?

@@ -133,18 +133,32 @@ Context.wrap = function(context) {
};

Context.prototype.get = function(key) {
var bind = function(context, func){
return function(){
Copy link
Contributor

Choose a reason for hiding this comment

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

can we move this out of get?

Copy link
Author

Choose a reason for hiding this comment

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

Where would you like it?

Copy link
Contributor

Choose a reason for hiding this comment

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

one more q:
would not the following need the same check?

Context.prototype.getBlock = function(key, chk, ctx) {
if (typeof key === "function") {
key = key(chk, ctx).data;
chk.data = "";
}

dynamic partials

if (typeof elem === "function") {
return this.capture(elem, context, function(name, chunk) {
dust.load(name, chunk, context).end();
});

Copy link
Author

Choose a reason for hiding this comment

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

It might, I'll try and add a test for both.

Copy link
Author

Choose a reason for hiding this comment

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

Can you provide an example of a partial that includes a function? I'll work on this some more tomorrow - nap time.

Copy link
Contributor

Choose a reason for hiding this comment

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

sure :) thanks for your help.

I was hinting at the dynamic partials, {">partial{name}":overridecontext/} and the context itself been a function. I have not personally used this ( but the code supports it )

Copy link
Author

Choose a reason for hiding this comment

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

So where did you want the bind function?

Copy link
Author

Choose a reason for hiding this comment

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

Also I haven't ever used dynamic partials, and therefore my ability to write a test for them is minimal. As long as this code isn't breaking any existing tests, to do we need more tests? Can't someone using d-partials submit a bug if they're not working?

@vybs
Copy link
Contributor

vybs commented Sep 10, 2012

you can also create a new one if need be, since its been a plan to refactor the grammar and dust-core tests out.

@wshaver
Copy link
Author

wshaver commented Sep 10, 2012

How do I create a global context inside grammarTests.js? That's what I was not sure about before.

@vybs
Copy link
Contributor

vybs commented Sep 10, 2012

Ah, to simulate global context,

may be extend the to have a globalContext, just like we have context in the specs

Conflicts:
	lib/dust.js
	test/jasmine-test/spec/grammarTests.js
@wshaver
Copy link
Author

wshaver commented Sep 10, 2012

Actually we can do it by changing the order of the includes in the specRunner. Then you can have a test like:

  {
    name:     "test that deep stack functions have the correct scope",
    source:   "{getName1}{getName2}{getName3}",
    context:  (function(){
                var context = dust.makeBase({
                  name: '1Bob',
                  getName1: function(){ return this.name;}
                });
                var instance = context.push({
                  name: '2Joe',
                  getName2: function(){ return this.name;}
                });
                instance = instance.push({
                  name: '3Tim',
                  getName3: function(){ return this.name;}
                });
                return instance;
              }()),
    expected: "1Bob2Joe3Tim",
    message: "Should allow for deep stack functions"
  }

while(ctx) {
if (ctx.isObject) {
value = ctx.head[key];
if (!(value === undefined)) {
if(typeof value === 'function'){
Copy link
Contributor

Choose a reason for hiding this comment

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

another note: in order to distinguish between the dust compiler created functions and the lambda's that can exist as part of the context , we have
the elem.isFunction check

see the tap method fyi

Copy link
Author

Choose a reason for hiding this comment

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

I'm not quite sure what you're saying here. The value here is likely outside of dust as it can be part of the 'context'.

@vybs
Copy link
Contributor

vybs commented Sep 11, 2012

@wshaver do let me know when this is good to be reviewed.

@ghost ghost assigned vybs Sep 11, 2012
@vybs
Copy link
Contributor

vybs commented Nov 13, 2012

ping? @wshaver

@wshaver
Copy link
Author

wshaver commented Jan 10, 2013

Hey there, sorry I've been busy with other projects. I've dumped my fork and rebuilt it. Should I issue a separate pull request?

@vybs
Copy link
Contributor

vybs commented Jan 10, 2013

Welcome back ! sure with the changes we talked about:)

@wshaver
Copy link
Author

wshaver commented Jan 10, 2013

I asked a couple of other comments above clarifying the changes you want.

@vybs vybs closed this Mar 20, 2013
@vybs
Copy link
Contributor

vybs commented Mar 20, 2013

closed, since it is unclear if this is a priority to fix.

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.

5 participants