Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

init

  • Loading branch information...
commit 9e3e3a642f9ed073e1c6cca78cc8577737d0a14d 0 parents
@clyfe authored
1  .gitignore
@@ -0,0 +1 @@
+/node_modules
77 README.md
@@ -0,0 +1,77 @@
+### About
+
+Meta Code is a set of metaprogramming utilities for CoffeeScript (inspired by Ruby).
+
+Although you can achieve the same things by hard-coding evrything, this package is good
+because function names convey meaning, and is good to have consensus among developers.
+
+
+### Features
+
+Curently, the folowing tools are provided (nicely documented in the code)
+
+* **module**
+ - `extend` - copies the module object's methods onto an object
+ - `include` - copies the module object's methods onto an object's prototype
+ - `includeInter` - inject a shallow copy of the module object into an object's prototype chain
+
+* **forward**
+ - `forward` - forward a method call to an object property
+
+* **autoload**
+ - `autoload` - load a property from a file
+
+
+### Install
+
+Install with npm:
+
+```shell
+# install locally in "./node_modules"
+npm install meta_code
+
+# or use -g to install globally
+npm install meta_code -g
+
+# or add it as a dependecy to your package.json and run
+npm install
+```
+
+
+### Usage
+
+Metacode consists of a series of tools like "forward" or "module" that aid you to inject code in your objects.
+There are two interfaces that can be used:
+
+1. Use via `metaCode` helper
+
+```coffeescript
+metaCode = require 'meta_code'
+
+# a "module" we'll be including in our class
+Power =
+ sword: 'katana'
+ fight: -> console.log @sword
+
+class Samurai
+ # Enable the module tool. Once enabled we can use this tool's methods
+ # like 'extend' and 'include' in our object, because the tool's methods
+ # get copied in our object
+ metaCode @, 'module'
+ @include Power
+```
+
+2. Use directly
+
+```coffeescript
+module = require 'meta_code/tools/module' # include the tool
+
+# a "module" we'll be including in our class
+Power =
+ sword: 'katana'
+ fight: -> console.log @sword
+
+class Samurai
+ module.include.call @, Power
+```
+
33 index.coffee
@@ -0,0 +1,33 @@
+# A set of metaprogramming tools to aid development, inspired by Ruby
+
+
+# Use this function to enable a set of metacode tools in your class
+#
+# class Controller
+# metaCode @, 'forward'
+# @forward 'req', 'param', 'session'
+#
+# c = new Controller()
+# c.req = someReq
+# c.param 'x' # forwards call to "req" object
+#
+# @object {Object} the class (in CoffeeScript sense) to be augmented
+# @modules {Strings...} the modules to bring in
+# @api public
+metaCode = (object, tools...) ->
+ for toolName in tools
+ tool = require metaCode.loadPath + toolName
+ object[method] = tool[method] for own method of tool
+
+
+# Default load path, can be customized for custom needs or testing
+# Example values
+#
+# "./tools/"
+# __dirname + "/tools"
+#
+metaCode.loadPath = "./tools/"
+
+
+module.exports = metaCode
+
26 package.json
@@ -0,0 +1,26 @@
+{
+ "author": "Nicolae Claudius",
+ "name": "meta_code",
+ "description": "Metaprogramming utilities for CoffeeScript",
+ "version": "0.0.1",
+ "keywords": ["metaprogramming", "coffeescript"],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/clyfe/meta_code.git"
+ },
+ "main": "index",
+ "scripts": {
+ "test": "expresso"
+ },
+ "engines": {
+ "node": "~v0.4.9"
+ },
+ "dependencies": {
+ "coffee-script": ">= 1.1.1",
+ "underscore": ">= 1.1.7"
+ },
+ "devDependencies": {
+ "expresso": ">= 0.8.1"
+ }
+}
+
10 test/autoload.test.coffee
@@ -0,0 +1,10 @@
+assert = require 'assert'
+metaCode = require '../index'
+
+# test the forward tool
+exports.autoload = ->
+ class C
+ metaCode @, 'autoload'
+ @autoload 'sample_module', __dirname + '/autoload/sample_module'
+ assert.equal C.sample_module, 1
+
1  test/autoload/sample_module.coffee
@@ -0,0 +1 @@
+module.exports = 1
16 test/forward.test.coffee
@@ -0,0 +1,16 @@
+assert = require 'assert'
+metaCode = require '../index'
+
+# test the forward tool
+exports.forward = ->
+ property =
+ method1: -> 'method1'
+ method2: -> 'method2'
+ class C
+ metaCode @, 'forward'
+ @forward 'property', 'method1', 'method2'
+ constructor: (@property) ->
+ c = new C(property)
+ assert.equal c.method1(), 'method1'
+ assert.equal c.method2(), 'method2'
+
9 test/meta_code.test.coffee
@@ -0,0 +1,9 @@
+assert = require 'assert'
+metaCode = require '../index'
+
+# test the metacode tool importer
+exports.metaCode = ->
+ class C
+ metaCode @, 'forward'
+ assert.ok C.forward
+
17 tools/autoload.coffee
@@ -0,0 +1,17 @@
+# Forward method calls to certain properties.
+#
+# class I18n
+# metaCode @, 'autoload'
+# @autoload 'Backend', 'lib/backend'
+#
+# console.log I18n.Backend
+#
+# @name {String} the name of the property onto wich we load
+# @methods {path} the path to be required
+# @api public
+autoload = (name, path) ->
+ @__defineGetter__ name, -> require path
+
+
+exports.autoload = autoload
+
24 tools/forward.coffee
@@ -0,0 +1,24 @@
+# Forward method calls to certain properties.
+#
+# class Controller
+# metaCode @, 'forward'
+# @forward 'req', 'param', 'session'
+#
+# same as
+#
+# class Controller
+# param: -> @req.param.apply @req, arguments
+# session: -> @req.session.apply @req, arguments
+#
+# @object {String} the name of the property to forward calls to
+# @methods {Strings...} the methods to be wired
+# @api public
+forward = (property, methods...) ->
+ proto = @::
+ for method in methods
+ do (method) ->
+ proto[method] = -> @[property][method].apply @[property], arguments
+
+
+exports.forward = forward
+
73 tools/module.coffee
@@ -0,0 +1,73 @@
+_ = require 'underscore'
+
+
+# Copy into object all properties from module
+#
+# Macros =
+# delegate: (to, what) ->
+# @[what] = @[to][what].apply @[to], arguments
+#
+# class Application extends Controller
+# metaCode @, 'module'
+# @extend Macros
+# @delegate 'req', 'userId'
+# index: -> console.log @userId()
+#
+# @objects {Objects...} the objects to extend with
+# @api public
+extend = (objects...) ->
+ for object in objects
+ for name, property of object
+ @[name] = property
+
+
+# Copy into object all properties from module onto the prototype
+#
+# Authentication =
+# currentUser: (cb) ->
+# User.find @session('userId'), (err, user) ->
+# user = new User() if err
+# cb(user)
+#
+# Authorization =
+# authorize: (role, cb) ->
+# @currentUser (user) ->
+# throw new Error('Not Authorized') unless user.role == role
+# cb()
+#
+# class Tweets extends Controller
+# metaCode @, 'module'
+# @include Authentication, Authorization
+# show:
+# @authorize 'admin', =>
+# Tweet.find @params 'id', (@err, @tweet) => @render 'show'
+#
+# @objects {Objects...} the objects to mix in
+# @api public
+include = (objects...) ->
+ proto = @::
+ for object in objects
+ for own name, property of object
+ proto[name] = property
+
+
+# The same as "include" only it does not copy the properties, it achieves
+# augmentation by injecting copies of module-objects into the receiver's
+# prototype chain
+#
+# @objects {Objects...} the objects to mix in
+# @api public
+includeInter = (objects...) ->
+ for object in objects
+ module = _.clone(object)
+ previousPrototype = @::
+ @:: = module
+ module.__proto__ = previousPrototype
+ # make sure to preserve the constructor property
+ @::constructor = previousPrototype.constructor if previousPrototype.hasOwnProperty 'constructor'
+
+
+exports.extend = extend
+exports.include = include
+exports.includeInter = includeInter
+
Please sign in to comment.
Something went wrong with that request. Please try again.