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

Nested mixins cannot be accessed inside objects iteration #1606

Closed
maxim-grishaev opened this issue Jul 28, 2014 · 8 comments
Closed

Nested mixins cannot be accessed inside objects iteration #1606

maxim-grishaev opened this issue Jul 28, 2014 · 8 comments

Comments

@maxim-grishaev
Copy link

mixin ul(li, t)
    ul
        each val, name in t
            +li(name, val)

mixin li(name, val)
    li= name

+ul(li, {a:1})

Fails with Object #<Object> has no method 'li'.

Whereas the same code but with Array works pretty good:

mixin ul(li, t)
    ul
        each val, name in t
            +li(name, val)

mixin li(name, val)
    li= name

+ul(li, [1,2])

gives

<ul>
<li>1</li>
<li>2</li>
</ul>
@ForbesLindesay
Copy link
Member

Using the latest version of jade, your first example outputs:

<ul>
  <li>a</li>
</ul>

If you still believe there is an error, please provide a failing test case (preferably as a pull request).

@maxim-grishaev
Copy link
Author

Not sure what the difference between these examples, but this one fails:

- var dbg = {a:1, b:2, c:3}

mixin eachDbg(mxn)
    ul
        each val, name in dbg
            +mxn(name, val)

foo
    mixin tab(name, val)
        tab: a(href="##{name}")= name
    +eachDbg(tab)
    //
    mixin pane(name, val)
        h2= name
        pane(id=id)= val
    +eachDbg(pane)

More info

➜  sync-viewer git:(master) ✗ npm i jade -g
/usr/local/bin/jade -> /usr/local/lib/node_modules/jade/bin/jade.js
[email protected] /usr/local/lib/node_modules/jade
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected], [email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected])
└── [email protected] ([email protected])
➜  sync-viewer git:(master) ✗ jade --version
1.1.5
➜  sync-viewer git:(master) ✗ which jade
/usr/local/share/npm/bin//jade
➜  sync-viewer git:(master) ✗ cat tmp/mixins.jade | jade

/usr/local/share/npm/lib/node_modules/jade/lib/runtime.js:202
  throw err;
        ^
TypeError: Jade:6
    4|     ul
    5|         each val, name in dbg
  > 6|             +mxn(name, val)
    7|
    8| foo
    9|     mixin tab(name, val)

Object #<Object> has no method 'mxn'
    at Object.eval (eval at <anonymous> (/usr/local/share/npm/lib/node_modules/jade/lib/jade.js:160:8), <anonymous>:41:19)
    at Object.jade_mixins.eachDbg (eval at <anonymous> (/usr/local/share/npm/lib/node_modules/jade/lib/jade.js:160:8), <anonymous>:47:4)
    at eval (eval at <anonymous> (/usr/local/share/npm/lib/node_modules/jade/lib/jade.js:160:8), <anonymous>:79:23)
    at res (/usr/local/share/npm/lib/node_modules/jade/lib/jade.js:161:38)
    at Socket.<anonymous> (/usr/local/share/npm/lib/node_modules/jade/bin/jade.js:127:20)
    at Socket.emit (events.js:117:20)
    at _stream_readable.js:929:16
    at process._tickCallback (node.js:419:13)

@ForbesLindesay
Copy link
Member

Yes, because mixins are not variables like that. Instead they are their own special kind of construct. You could implement something like what you're after as:

  • var dbg = {a:1, b:2, c:3}

mixin eachDbg(mxn)
ul
each val, name in dbg
- mxn(name, val)

foo
    mixin tab(name, val)
        tab: a(href="##{name}")= name
    +eachDbg(jade_mixins['tab'])
    //
    mixin pane(name, val)
        h2= name
        pane(id=id)= val
    +eachDbg(jade_mixins['pane'])

// we are messing with jade internals (i.e. accessing jade_mixins directly)
// so we have to stop it from optimizing things
if false
  +#{''}

Note that if you do that, it could break with any version of jade, since jade_mixins is intended to be internal.

Alternatively, a simpler way is to use the fact that you can dynamically invoke mixins:

- var dbg = {a:1, b:2, c:3}

mixin eachDbg(mxn)
    ul
        each val, name in dbg
            +#{mxn}(name, val)

foo
    mixin tab(name, val)
        tab: a(href="##{name}")= name
    +eachDbg('tab')
    //
    mixin pane(name, val)
        h2= name
        pane(id=id)= val
    +eachDbg('pane')

Here, we pass the name of the mixin we want to invoke, and then we invoke it by name using +#{mxn}

@maxim-grishaev
Copy link
Author

Thank you @ForbesLindesay!

I actually already found yor second solution on SO =)
But as I see this, construction looks like a bunch of dark magic, so I made a "clumsy" feature request #1608
Actually, if blocks would be able to accept parameters like mixins, the whole problem would be solved...
Is there any solution for this in 2.0?

@maxim-grishaev
Copy link
Author

BTW, this solution isn't too fail-proof and any mistake in mixin name will lead to REALLY WEIRD errors

@ForbesLindesay
Copy link
Member

Yes, we could definitely do better with reporting errors for undefined mixins.

I quite like the suggestion in #1608 so may consider that feature in the future.We might also be able to use a similar idea to support multiple blocks in a single mixin (another feature request that comes up from time to time).

@maxim-grishaev
Copy link
Author

I quite like the suggestion in #1608 so may consider that feature in the future

Cool, thanks!

@Artazor
Copy link

Artazor commented Aug 13, 2014

Seems that I've implemented syntax/semantics very close to what is needed. You can check

pugjs/with#3 - here is description of what's done
https://github.com/Artazor/jade - my fork of jade (extended conservatively)

Waiting for @ForbesLindesay to take a look on the changes

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

No branches or pull requests

3 participants