Giter Site home page Giter Site logo

fence's Introduction

fence

Effortless way to avoid manual extern files when doing javascript interop from Clojurescript.

From a compromised Clojurik dictionary:

(Warning: This section is just for fun. Feel free to skip to main documentation ahead.)

fence (noun)

  1. a structure made of w̶o̶o̶d̶ ̶o̶r̶ ̶m̶e̶t̶a̶l̶ keystrokes etc that surrounds a piece of l̶a̶n̶d̶ code or prevents p̶e̶o̶p̶l̶e̶ ̶o̶r̶ ̶a̶n̶i̶m̶a̶l̶s̶ ̶f̶r̶o̶m̶ ̶e̶n̶t̶e̶r̶i̶n̶g̶ ̶o̶r̶ ̶l̶e̶a̶v̶i̶n̶g̶ javascript symbols from getting renamed
  1. someone who b̶u̶y̶s̶ ̶a̶n̶d̶ ̶s̶e̶l̶l̶s̶ ̶s̶t̶o̶l̶e̶n̶ ̶g̶o̶o̶d̶s̶ uses macros from a library with stolen code in it

fence (verb)

  1. to put a̶ ̶f̶e̶n̶c̶e̶ parentheses around something
  1. to fight with a l̶o̶n̶g̶ ̶t̶h̶i̶n̶ ̶s̶w̶o̶r̶d̶ short line of dots as a s̶p̶o̶r̶t̶ way to cure headaches
  1. to answer someone's questions in a c̶l̶e̶v̶e̶r̶ lazy way in order to g̶e̶t̶ ̶a̶n̶ ̶a̶d̶v̶a̶n̶t̶a̶g̶e̶ ̶i̶n̶ ̶a̶n̶ ̶a̶r̶g̶u̶m̶e̶n̶t̶ answer in advance with an FAQs section in README.

That random name is a complete mess ;)

Fence provides a fence.core/+++ macro that works like do special form. Wrap it around all your javascript interop forms to transform them automatically so you don't have to add extern files manually.

Usage

Add fence to your Clojurescript project:

[fence "0.2.0"]

Refer to fence.core/+++ in your namespace:

(ns hello
  "Calling property symbols that won't be renamed."
  (:require-macros [fence.core :refer [+++]]))

and wrap all renaming-sensitive forms inside fence.core/+++ which works like do special form.

forms that requires extern forms that works without extern
(. js/foo bar) (+++ (.. js/foo -bar))
(.-boo js/foo) (+++ (.. js/foo -boo))
(.bla js/foo) (+++ (.. js/foo bla))
(.bla js/foo x y z) (+++ (.. js/foo (bla x y z)))

Please note +++ use clojure.walk to transform all interop forms inside its body so the following should work too:

(defn foo []
  (+++
    (.-bar js/foo)
    (.moreForms js/foo)
    (at (any (level (.execute js/foo))))))

How it works

Imagine you have this piece of Clojurescript code:

(ns hello
  "Calling property symbols that WILL be renamed."
  )
(.. js/something -someAttributes aMethod (anotherMethod "arg1" "arg2"))

without extern file(s), the above code will end up with this:

something.d.b().c("arg1", "arg2");

which will fail to execute.

Instead of writing some extern files manually, just wrap that sensitive form inside fence.core/+++ like this:

(ns hello
  "Calling property symbols that won't be renamed."
  (:require-macros [fence.core :refer [+++]]))

(+++ (.. js/something -someAttributes aMethod (anotherMethod "arg1" "arg2")))

and here's (part of) the result:

(function() {
  var a;
  a = something.someAttributes;
  a = a.aMethod.call(a);
  return a.anotherMethod.call(a, "arg1", "arg2");
})();

Never be afraid of javascript interop again! ^^

More in-depth technical details:

fence.core/+++ transforms all interop forms found in its body code into fence.core/dot and fence.core/.. macros (fence version of . and ..) which in turn will expand to aget forms.

Clojurescript forms Output javascript Optimized in :advanced mode without extern Optimized with extern
(. js/foo bar) foo.bar renamed to a shorter name like foo.a foo.bar
(.-boo js/foo ) foo.boo renamed to a shorter name like foo.b foo.boo
(.bla js/foo) foo.bla() renamed to a shorter name like foo.c() foo.bla()
(.bla js/foo "x" 1) foo.bla("x", 1) renamed to a shorter name like foo.d("x", 1) foo.bla("x", 1)
Clojurescript forms Output javascript Optimized with/without extern
(+++ (.. js/foo bar)) foo["bar"] foo.bar
(+++ (.. js/foo -boo)) foo["boo"] foo.boo
(+++ (.. js/foo bla)) foo["bla"].call(foo) foo.bla.call(foo)
(+++ (.. js/foo (bla "x" 1))) foo["bla"].call(foo, "x", 1) foo.bla.call(foo, "x", 1)

FAQs

  1. Why not a reader macro?
  • I definitely want to but Clojurescript doesn't provide a convenient, sharable way to make reader macros like Clojure with data_readers.clj.
  1. Are there any performance pitfalls?
  • No. Google Closure compiler will replace string versions of properties to symbol versions so the final javascript will be the same as its counterpart using extern files.

Copyright

Copyright ©2014 Hoang Minh Thang

Distributed under the Eclipse Public License, the same as Clojure. Please see the epl-v10.html file at the top level of this repo.

fence's People

Contributors

myguidingstar avatar

Stargazers

Erich Ocean avatar Kvar Izunia avatar  avatar Thinh P. Tran avatar Tienson Qin avatar  avatar Adam Hill avatar Kirill Chernyshov avatar shaun avatar Paul Gowder avatar Gert Goet avatar Lucien Knechtli avatar Tommi Reiman avatar Luke Snape avatar ayato-p avatar  avatar ikarius avatar Tyler Anderson avatar Priyatam Mudi avatar Mattias Dalkvist avatar Yen-Chin,Lee avatar Ethan Sherbondy avatar  avatar Ed Babcock avatar Dan Kersten avatar Chris Truter avatar Roberto Guerra avatar  avatar David Powell avatar Dom Kiva Meyer avatar Mihael Konjević avatar Timo Sulg avatar Justin avatar Jordan Arentsen avatar Wei Hsu avatar Michael Drogalis avatar Michał Stachurski avatar Baptiste Fontaine avatar Nils Grünwald avatar Ducky avatar Lucas Bradstreet avatar Maksim Soltan avatar Myron Mavko avatar Boris Kourtoukov avatar Alexander Solovyov avatar Stepan Parunashvili avatar Gal Dolber avatar Alan Dipert avatar  avatar Ruslan Prakapchuk avatar  avatar Martin Klepsch avatar Jelle Akkerman avatar Atamert Ölçgen avatar Hoàng Minh Thắng avatar

Watchers

Orlin M Bozhinov avatar James Cloos avatar Hoàng Minh Thắng avatar Boris Kourtoukov avatar Thinh P. Tran avatar  avatar

fence's Issues

Unable to build: "java.io.FileNotFoundException: Could not locate clojure/tools/analyzer/env__init.class"

Including the project as a dependency causes compilation to fail, with the following error. I suspect it's a result of Clojure changing since this was produced?

Exception in thread "main" java.lang.ExceptionInInitializerError
	at clojure.main.<clinit>(main.java:20)
Caused by: java.io.FileNotFoundException: Could not locate clojure/tools/analyzer/env__init.class or clojure/tools/analyzer/env.clj on classpath., compiling:(clojure/core/async/impl/ioc_macros.clj:1:1)
	at clojure.lang.Compiler.load(Compiler.java:7526)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:370)
	at clojure.lang.RT.load(RT.java:460)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:619)
	at clojure.core.async$eval10741$loading__6434__auto____10742.invoke(async.clj:9)
	at clojure.core.async$eval10741.invokeStatic(async.clj:9)
	at clojure.core.async$eval10741.invoke(async.clj:9)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:370)
	at clojure.lang.RT.load(RT.java:460)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:1523)
	at figwheel_sidecar.repl$eval10712$loading__6434__auto____10713.invoke(repl.clj:1)
	at figwheel_sidecar.repl$eval10712.invokeStatic(repl.clj:1)
	at figwheel_sidecar.repl$eval10712.invoke(repl.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:370)
	at clojure.lang.RT.load(RT.java:460)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:1523)
	at figwheel_sidecar.system$eval10706$loading__6434__auto____10707.invoke(system.clj:1)
	at figwheel_sidecar.system$eval10706.invokeStatic(system.clj:1)
	at figwheel_sidecar.system$eval10706.invoke(system.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:370)
	at clojure.lang.RT.load(RT.java:460)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:930)
	at figwheel_sidecar.repl_api$eval1602$loading__6434__auto____1603.invoke(repl_api.clj:1)
	at figwheel_sidecar.repl_api$eval1602.invokeStatic(repl_api.clj:1)
	at figwheel_sidecar.repl_api$eval1602.invoke(repl_api.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:370)
	at clojure.lang.RT.load(RT.java:460)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at fttv.figwheel$eval1596$loading__6434__auto____1597.invoke(figwheel.clj:1)
	at fttv.figwheel$eval1596.invokeStatic(figwheel.clj:1)
	at fttv.figwheel$eval1596.invoke(figwheel.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:370)
	at clojure.lang.RT.load(RT.java:460)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:457)
	at user$eval13$loading__6434__auto____14.invoke(user.clj:1)
	at user$eval13.invokeStatic(user.clj:1)
	at user$eval13.invoke(user.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:366)
	at clojure.lang.RT.maybeLoadResourceScript(RT.java:362)
	at clojure.lang.RT.doInit(RT.java:482)
	at clojure.lang.RT.<clinit>(RT.java:336)
	... 1 more
Caused by: java.io.FileNotFoundException: Could not locate clojure/tools/analyzer/env__init.class or clojure/tools/analyzer/env.clj on classpath.
	at clojure.lang.RT.load(RT.java:463)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6548.invoke(core.clj:6046)
	at clojure.core$load.invokeStatic(core.clj:6045)
	at clojure.core$load.doInvoke(core.clj:6029)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5848)
	at clojure.core$load_one.invoke(core.clj:5843)
	at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
	at clojure.core$load_lib.invokeStatic(core.clj:5887)
	at clojure.core$load_lib.doInvoke(core.clj:5868)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5925)
	at clojure.core$load_libs.doInvoke(core.clj:5909)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5947)
	at clojure.core$require.doInvoke(core.clj:5947)
	at clojure.lang.RestFn.invoke(RestFn.java:930)
	at clojure.core.async.impl.ioc_macros$eval11351$loading__6434__auto____11352.invoke(ioc_macros.clj:12)
	at clojure.core.async.impl.ioc_macros$eval11351.invokeStatic(ioc_macros.clj:12)
	at clojure.core.async.impl.ioc_macros$eval11351.invoke(ioc_macros.clj:12)
	at clojure.lang.Compiler.eval(Compiler.java:7062)
	at clojure.lang.Compiler.eval(Compiler.java:7051)
	at clojure.lang.Compiler.load(Compiler.java:7514)
	... 174 more
Subprocess failed

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.