malgorithms / toffee

a NodeJS and browser templating language based on coffeescript, with the slickest syntax ever
MIT License
174 stars 10 forks source link

Any chance you would support macros? #17

Closed mkoryak closed 11 years ago

mkoryak commented 11 years ago

Your lib looks great, but any chance it will support macros? I macro is like a function that you define that outputs a block of html based on some arguments you provide to it.

It becomes even more useful when you can import a bunch of macros from a template into another template.

malgorithms commented 11 years ago

Hmm, interesting, I need to think about this. Is there something this offers you that normal partial calls don't? If the goal of a macro is to take some input vars and return a block of HTML, it sounds just like a call to partial.

In fact, partial actually "returns" the output, and you can print it using #{} or just use its output inside {# #}. For example, you can assign it to a variable and do what you want with it.

{#
  x = partial './hello_world.toffee', name: 'chris'
  x = x.replace 'Hello', 'Goodbye'
  print x.toUpperCase() + '!'
#}

Basically, hello_world.toffee itself is a macro as you describe it, I think. Here is the inside of hello_world:

Well, hello there #{name}.

It could be more complicated logic, of course, using whatever vars you pass.

The only difference I can think of from what you describe is that you might define multiple of these macros in one file, rather than have one per file. From an organizational standpoint I don't really have strong feelings about this, but it might be a bunch of work to get added, for subtle reasons. I'd probably have to introduce a new function, like load which does some different things.

Btw, in the short term, you can still define multiple functions in one file simply by putting them all in an object and passing the name of the one you wish to call. Here's a macro system, sorta:

macros.toffee

{#
  macro_fns = 

    hello_world: ->
      {:
        Well, hello there, #{arg.name}.
      :}

    half: -> {:#{(arg.x)/2}:}

  if macro_fns[macro]? then macro_fns[macro]()

#}

a page that uses them


A message to Chris:

#{partial './macros.toffee', {macro: "hello_world", arg: {name: "Chris"}  } }

4 divided by 2

#{partial './macros.toffee', {macro: "half", arg: {x: 4} } }

Anyway, curious all your thoughts about all this. I'll think about it too.

mkoryak commented 11 years ago

This is pretty close, there are some differences between this approach and the functionality I associate with macros. Namely:

None of these are show stoppers, but they do present usability issues.


Could you support having coffee functions on the page itself? I shalt read your code and see why you didnt do this yet :)

malgorithms commented 11 years ago

Hi @mkoryak - I'm not following your last question. You mean something like this? The following defines a function in CoffeeScript (one that outputs using toffee syntax) and then uses it.

{#
    half = (some_num) ->
       {:
          <p> Did you know? Half of #{some_num} is #{some_num / 2}.</p>
       :}
#}

<h1>Demo</h1>
{# half(10) #}
malgorithms commented 11 years ago

Btw, this technique of defining a function and using it throughout the page is pretty common in Toffee usage, at least among the users I know. Do you think it was unclear this was possible, given the Readme? If so, I should update it.

For example, if you have an array of objects and want to print them in a table or some other repeated dom structure, it's often helpful to define a print_whatever_row() function, and use that.

You might see this in a .toffee file:

{#
   print_user = (u) ->
      {: 
         <li>
          #{u.name} - #{u.age}
          {# whatever other logic you want, printing custom rows #}
         </li>
      :}
#}

<h3>USERS</h3>
<ul class="users">
 {#
     for u in users
        print_user u
 #}
</ul>

<h3>ADMINS</h3>
<ul class="admins">
 {#
     for u in admins
        print_user u
 #}
</ul>

This works really well and is used a lot. Then, if some fn is important enough that it's used in multiple files, that's when I'd argue it typically deserves its own file. This is just a style opinion of my own, but deviating from it also has technical considerations, and I would like to keep Toffee simple.

mkoryak commented 11 years ago

I confess that i didnt read the entire readme from start to end, i skimmed it. I did looked for being able to include functions in the coffee code. I searched the readme for the word "function" and couldnt find what i was looking for where it was used.

I think as it stands, your code supports everything i need, thank you for answering all of my questions