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

Method Macro Expansion proposal #1

Closed
wants to merge 1 commit into from
Closed

Method Macro Expansion proposal #1

wants to merge 1 commit into from

Conversation

xkxx
Copy link

@xkxx xkxx commented Nov 7, 2013

Hello there,

I would like to propose adding support for method macros. They are similar to normal macros, except they take an extra object argument and are used in place of methods. This pull requests implements a rough example implementation of the concept. I used macro.defmethod to denote method macro in my implementation, but it serves as a placeholder only and the actual keyword is open for suggestion.

A short example (setting/getting DOM data-* fields):

macro.defmethod $data (el, name, val) ->
        if val?
                macro.codeToNode(-> el.dataset[name] = val).subst {el: el, name: name, val: val}
        else
                macro.codeToNode(-> el.dataset[name]).subst {el: el, name: name}

A more extensive example and my main use case for this feature, a JQuery-like utility that compiles to bare-bone HTML5:

macro $id (id) ->
    macro.codeToNode(-> document.getElementById id).subst {id: id}
macro $tag (name) -> 
    macro.codeToNode(-> document.getElementsByTagName name).subst {name: name}
macro $class (name) ->
    macro.codeToNode(-> document.getElementsByClassName name).subst {name, name}
macro $query (q) ->
    macro.codeToNode(-> document.querySelector q).subst {q, q}
macro $queryAll (q) ->
    macro.codeToNode(-> document.querySelectorAll q).subst {q, q}

macro.defmethod $data (el, name, val) ->
    if val?
        macro.codeToNode(-> el.dataset[name] = val).subst {el: el, name: name, val: val}
    else
        macro.codeToNode(-> el.dataset[name]).subst {el: el, name: name}

macro.defmethod $css (el, name, val) ->
    if val?
        macro.codeToNode(-> el.style.setPropertyValue(name)).subst {el: el, name: name, val: val}
    else
        macro.codeToNode(-> el.style.getPropertyValue(name)).subst {el: el, name: name}

macro.defmethod $hasClass (el, name) ->
    macro.codeToNode(-> el.classList.contains(name)).subst {el: el, name: name}

macro.defmethod $addClass (el, name) ->
    macro.codeToNode(-> el.classList.add(name)).subst {el: el, name: name}

macro.defmethod $toggleClass (el, name) ->
    macro.codeToNode(-> el.classList.toggle(name)).subst {el: el, name: name}

macro.defmethod $removeClass (el, name) ->
    macro.codeToNode(-> el.classList.remove(name)).subst {el: el, name: name}

$id("myform").$data "user", "foo"
$id("important_text").$css "fontSize", "24px"

@vanviegen
Copy link

Hey @xkxx,

Thanks for your pull request. I'm not really convinced that macro-methods would be a good idea though... in your example, it looks like $data should be somehow part of the specific object (or class) you calling it on. In fact, it behaves more like a global function. Wouldn't it be less confusing to just create a regular macro that takes the element as its first argument?

Regardless, if you really want this type of syntax for some sort of DSL, you could just implement defmethod using a regular macro that takes an AST to be walked. (Just like macro is itself a macro.) Would that work for you?

Looking over your patch, you're right that the implementation should be using hasOwnProperty for looking up macros. I'll do that the next version.

@xkxx
Copy link
Author

xkxx commented Nov 8, 2013

A macro method is simply a syntax sugar for method(self, args...), but I would argue that it is an important one. Looking at other languages like Julia, Lua and Nimrod, they have methods are expressed in a similar fashion. It is true that we can use method(self, args...) rather than self.method(args...), but it makes it harder to see the program's flow with currying involved. Here is an example:

# without method macro

 $insert(
   $css(
     $toggleClass(
        $removeClass(
          $remove($id "element"), "a-class"),
          "another-class"),
         "border",
       "solid 1px #fff"),
  $id("root"))

# with method macro

$id("element").$remove().$removeClass("a-class").$toggleClass("another-class").$css("border", "solid 1px $fff").$insert($id("root"))

@vanviegen
Copy link

@xkxx, I see your point about method-syntax being convenient. But I hope you see my point as well: using method-syntax for what are basically global functions can be pretty confusing.

Anyway, if you want to use this for a DSL or something like that, you can still use macros to implement this syntax. I'm closing this issue as a wontfix for now.

@vanviegen vanviegen closed this Nov 25, 2013
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.

2 participants