Is there any intrinsic support for namespacing in coffeescript?
Adequate namespacing seems like something coffeescript could really help with although I don't seem to be able to find anything to suggest that there is support for this.
I prefer using this pattern for "namespacing". It isn't really a namespace but an object tree, but it does the job:
Somewhere in the startup of the app, you define the namespaces globally (replace window with exports or global based on your environment.
window.App =
Models: {}
Collections: {}
Views: {}
Then, when you want to declare classes, you can do so:
class App.Models.MyModel
# The class is namespaced in App.Models
And when you want to reference it:
myModel = new App.Models.MyModel()
If you don't like the global way of defining namespaces, you can do so before your class:
window.App.Models ?= {} # Create the "namespace" if Models does not already exist.
class App.Models.MyModel
A way to make it simple to reference the class both in it's own "namespace" (the closed function) and the global namespace is to assign it immediately. Example:
# Define namespace unless it already exists
window.Test or= {}
# Create a class in the namespace and locally
window.Test.MyClass = class MyClass
constructor: (#a) ->
# Alerts 3
alert new Test.MyClass(1).a + new MyClass(2).a
As you see, now you can refer to it as MyClass within the file, but if you need it outside it's available as Test.MyClass. If you only want it in the Test namespace you can simplify it even more:
window.Test or= {}
# Create only in the namespace
class window.Test.MyClass
constructor: (#a) ->
Here's my personal implementation :
https://github.com/MaksJS/Namespace-in-CoffeeScript
How to use in the browser :
namespace Foo:SubPackage1:SubPackage2:
class Bar extends Baz
#[...]
How to use in CommonJS environment :
require './path/to/this/file' # once
namespace Foo:SubPackage1:SubPackage2:
class Bar extends Baz
#[...]
From the section about namespacing on the wiki: https://github.com/jashkenas/coffee-script/wiki/FAQ
# Code:
#
namespace = (target, name, block) ->
[target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
top = target
target = target[item] or= {} for item in name.split '.'
block target, top
# Usage:
#
namespace 'Hello.World', (exports) ->
# `exports` is where you attach namespace members
exports.hi = -> console.log 'Hi World!'
namespace 'Say.Hello', (exports, top) ->
# `top` is a reference to the main namespace
exports.fn = -> top.Hello.World.hi()
Say.Hello.fn() # prints 'Hi World!'
You must really check out CoffeeToaster:
https://github.com/serpentem/coffee-toaster
It comes with a packaging system that when enabled will use your folder's hierarchy as namespaces declarations to your classes if you want so, then you can extends classes from multiple files, do imports and son, such as like:
#<< another/package/myclass
class SomeClass extends another.package.MyClass
The build configuration is extremely minimalist and simple, made to be obvious:
# => SRC FOLDER
toast 'src_folder'
# => VENDORS (optional)
# vendors: ['vendors/x.js', 'vendors/y.js', ... ]
# => OPTIONS (optional, default values listed)
# bare: false
# packaging: true
# expose: ''
# minify: false
# => HTTPFOLDER (optional), RELEASE / DEBUG (required)
httpfolder: 'js'
release: 'www/js/app.js'
debug: 'www/js/app-debug.js'
There's also a debug option that compile files individually for ease the debugging processes and another useful features.
Hope it helps.
Note that it is possible to write:
class MyObject.MyClass
constructor: () ->
initializeStuff()
myfunction: () ->
doStuff()
if you declared an object/ns MyObject.
And while we're at it, here's my implementation of a jquery-ns-function:
(function($) {
$.namespace = function(namespace, initVal) {
var nsParts = namespace.split("."),
nsPart = nsParts.shift(),
parent = window[nsPart] = window[nsPart] || {},
myGlobal = parent;
while(nsPart = nsParts.shift()) {
parent = parent[nsPart] = parent[nsPart] || {};
}
return myGlobal;
}
})(jQuery);
I Strongly suggest using requirejs.org or similar battle tested module loaders.
Especially if you want to load stuff asynchronously.
Rolling your own namespacing/module scheme is really hard if you disregard
the simply, easy and naive approaches
As I'm also busy to learn the best way of structuring the files and use coffeescript in combination with backbone and cake, I have created a small project on github to keep it as a reference for myself, maybe it will help you too around cake and some basic things. All .js (with cake compiled files) are in www folder so that you can open them in your browser and all source files (except for cake configuration) are in src folder. In this example, all .coffee files are compiled and combined in one output .js file which is then included in html.
Based on some of the answers here on StackOverflow I have created small util.coffee file (in src folder) that exposes "namespaces" to the rest of the code.
Related
While learning coffeescript, I'm trying to create an instance of class A inside a method of class B, this is the code:
class #A
constructor: (#x) ->
show: ->
alert #x
class #B
constructor: (#y) ->
show: ->
a = new #A("eric")
alert a.x
alert #y
b = new #B("daniel")
b.show()
the error is TypeError: undefined is not a function.
Any help is appreciated.
Thanks
You have two problems:
# is just another way of saying this in CoffeeScript. That's all it means.
Classes are (more or less) just variables or properties like any other in CoffeeScript.
So when you say #A, you're just looking for the A property of this and your show is really saying:
a = new this.A("eric")
In that context, # will be an instance of B and Bs don't have A properties. Instead you should just say:
a = new A('eric')
Using # when defining a class:
class #A
#...
is just a way to make a class globally available. At the top level, # will (almost always) be window in a browser so you're really saying:
class window.A
#...
and window properties are globals. Keep in mind that each CoffeeScript file is wrapped in a function when it is converted to JavaScript:
Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.
So if you just said:
class A
then A would only be available to other code in that file. Saying:
class #A
makes A global.
If you're only working with one file then you don't need the #s on your classes:
class A
constructor: (#x) ->
show: ->
alert #x
class B
constructor: (#y) ->
show: ->
a = new A("eric")
alert a.x
alert #y
b = new B("daniel")
b.show()
Don't get in the habit of prefixing everything with #, only use it on classes when you need it and you know exactly what it will do. Even when you need it, there are better ways: use require.js to manage your dependencies, use an global application-specific object to manage scopes, ...
I want to join (use) classe in Coffescript files, and i found some usefull ideas here (sry for not including all links), since none fitted my needs (at least not as i like) I tried to find an own solution, this will work fine, but is there something I have overseen?
following "base" and "base class" are not OO words, I just did not find better names
I have a base (class) file TechDraw
class TechDraw
constructor: ->
$(window).load () =>
... do somthing
wave_to_me: ->
say 'I wave' # say is a basic func, I always use for debugging (console.log)
#TechDraw = new TechDraw
this works fine
Now I want to expand/extend my class with "sub classes/modules" in other files; ie. I have a TechDrawLine, and a TechDrawCalc, ans so on
What I did, was building a coffee file for each of them like:
class TechDrawConnector
constructor: (p)->
#parent=p
wave: (msg) ->
say 'yes its me, the connector:',msg
`window.TechDrawConnector = function(p) { return new TechDrawConnector(p) };`
# the last instead of a simple new like
# #TechDrawConnector = new TechDrawConnector
and my base(ic) class/module I extendet like this:
class TechDraw
constructor: ->
$(window).load () =>
#Connector=window.TechDrawConnector(this)
#LineGuy=window.TechDrawLineGuy(this)
#Connector.wave('init')
Since I am a newbee in coffeescript (yes javascript also) my solution feels to simple ...
Have I overseen somthing? The Polution of the global namespace is not so bad I think
You cant create an "extension" that way.
If you define the same class in the same namespace a second time the first class will simply be overwritten and become in accessible. This will mostly be dependent on the order of loading of the compiled JavaScript files.
However you could either later add an method to the prototype of the class
#file a.coffee
class A
constructor: ->
#foo()
#file B.coffee
A::foo = -> #do something
However this is no good style and can certainly be very confusing some time and lead to brittle errors.
Better would be to use a form of dependency injection
#file a.coffee
class A
constructor: (#closure) ->
$(window).load () => #closure()
#file B.coffee
new A () ->
#Connector=window.TechDrawConnector(#)
#LineGuy=window.TechDrawLineGuy(#)
#Connector.wave('init')
Darts Mirrors are for me currently poorly documented and very difficult to experiment with - they behave differently in code than from within the console.
for my own use, I would love to be able to treat classes (Types) as a trees, with a node being something like:
class Node {
type ... <== Type itself
name ... <== name of current class
super ... <== super of this class, eg, extends super
mixins ... <== mixins used to build this Type
extendChildren ... <== Types for which this type is super
mixinChildren ... <== Types for which this type is a mixin
}
for the life of me, I cannot get something this basic out of current Mirrors. hoping that somebody smarter than me has given it a shot!!
Below is a simple example which prints the name of the superclass and the name of Foo's members.
Note that the API uses Symbols, not strings. These are required so that dart2js can minify code that uses mirrors, they're a bit of a pain, but they mean that your code will run cross browser, and be compact.
To convert between symbols and strings see MirrorSystem.getName() and MirrorSystem.getSymbol() (Actually I believe you can just use new Symbol('foo') now).
Also note a new feature was recently added giving a special literal syntax for symbols. Up until recently you needed to type const Symbol('foo'), now just #foo, you may see a mix of old an new when looking at examples.
See this article for more information about mirrors.
Warning - probably a few typos in the example.
import 'dart:mirrors';
class Bob {
}
class Foo extends Bob {
String bar = 'jim';
}
main() {
var classMirror = reflectClass(Foo);
print(MirrorSystem.getName(classMirror.superClass.simpleName));
classMirror.declarations.values.forEach((d) => print(MirrorSystem.getName(d.simpleName)));
}
Update: Based on what Alan said below (Also untested):
Example source:
library foo;
class B extends A {
}
class A {
}
Definition:
List<ClassMirror> findSubClasses(Symbol libraryName, ClassMirror superClass) =>
currentMirrorSystem().findLibrary(libraryName).declarations.values
.where((d) => d is ClassMirror
&& d.superClass.simpleName == superClass.simpleName);
Usage:
var cm = reflectClass(A);
var subclasses = findSubClasses(#foo, cm);
There is a #MirrorsUsed attribute that you may want to experiment with if you're interested on compiling to js. It's still experimental so expect this to change.
I have found some TclOO resources that mention you can create subclasses of ::oo::class. You can also create bare objects using ::oo::object create, but you cannot migrate from a bare class to a real class (ie parent oo::object to parent oo::class)
I'm looking to create a DSL for defining modules, that just creates class definitions.
module create mysql 5.5 {
executable mysqld
method post_install { ... }
}
module create redis 2.6 {
executable redis-server
...
}
These could then be used as
set mod [mysql new]
$mod install
$mod post_install
While you can't make class-specific extension commands directly in the oo::define system, you can do the next-best-thing very easily. The trick is to use namespace path to profile-in the additional commands to the namespace just for the duration of the definition processing. Which is somewhat over-fancy way of saying that it's pretty easy in metaclass constructors to do this sort of stuff:
# First, build the definition of the extensions
namespace eval ::ModuleDefineExtensions {
proc executable {program} {
# I'm not quite sure how you want to handle this, but [uplevel] and
# [info level] will reveal what you need.
puts "define executable as $program here"
}
}
# Now, the [module] metaclass
oo::class create module {
superclass oo::class
constructor {definitionScript} {
# Save the old path
set oldpath [namespace eval ::oo::define {namespace path}]
# Set the new one
namespace eval ::oo::define {namespace path ::ModuleDefineExtensions}
# Now let the superclass constructor handle this, trapping errors
catch {next $definitionScript} msg opt
# Restore the old path
namespace eval ::oo::define [list namespace path $oldpath]
# Rethrow any errors
return -options $opt $msg
}
}
You probably need some more bits and pieces (e.g., a suitable default superclass of module classes that defines common methods) but those are conventional.
If you're using 8.6, the module definition can be simpler (this time without comments):
oo::class create module {
superclass oo::class
constructor {definitionScript} {
set oldpath [namespace eval ::oo::define {namespace path}]
namespace eval ::oo::define {namespace path ::ModuleDefineExtensions}
try {
next $definitionScript
} finally {
namespace eval ::oo::define [list namespace path $oldpath]
}
}
}
It's the same in principle, but uses the try/finally command of 8.6.
I have an external file where I have defined my class:
class MyClass
constructor: ->
alert 'hello'
When the CoffeeScript is compiled into JavaScript, it wraps it with a closure. So when I try to use it in some JavaScript:
$(function(){
var ob = new MyClass();
});
I get the error:
Uncaught ReferenceError: MyClass is not defined
but if I prefix the class name with window, it will work:
class window.MyClass
constructor: ->
alert 'hello'
How can I define my class without prefixing with window?
You can compile the CoffeeScript with the --bare but that's generally not recommended because you may pollute the global namespace.
My suggestion is to attach the class to the window object, like your second example, or even better, use this namespace function from the CoffeeScript docs to attach your classes to a single global object attached to the window
namespace = (target, name, block) ->
[target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
top = target
target = target[item] or= {} for item in name.split '.'
block target, top
# Usage:
#
namespace 'Hello.World', (exports) ->
# `exports` is where you attach namespace members
exports.hi = -> console.log 'Hi World!'
namespace 'Say.Hello', (exports, top) ->
# `top` is a reference to the main namespace
exports.fn = -> top.Hello.World.hi()
Say.Hello.fn() # prints 'Hi World!'
Source: CoffeeScript FAQ