{"id":26238474,"url":"https://github.com/hubspot/mixen","last_synced_at":"2025-04-22T23:46:32.106Z","repository":{"id":10317669,"uuid":"12444861","full_name":"HubSpot/mixen","owner":"HubSpot","description":"Combine Javascript classes on the fly","archived":false,"fork":false,"pushed_at":"2014-07-21T15:54:59.000Z","size":1198,"stargazers_count":85,"open_issues_count":4,"forks_count":2,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-13T07:11:22.205Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://github.hubspot.com/mixen","language":"CoffeeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HubSpot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-08-28T21:17:33.000Z","updated_at":"2021-06-14T02:38:01.000Z","dependencies_parsed_at":"2022-08-30T14:51:25.579Z","dependency_job_id":null,"html_url":"https://github.com/HubSpot/mixen","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fmixen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fmixen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fmixen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fmixen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HubSpot","download_url":"https://codeload.github.com/HubSpot/mixen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250343890,"owners_count":21415036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-13T06:16:07.850Z","updated_at":"2025-04-22T23:46:32.082Z","avatar_url":"https://github.com/HubSpot.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Mixen\n==================== \n\nMixen lets you combine classes on the fly.  With it you can build smaller, easier to understand and\nmore testable components, and more easily share code with others.  **It does not just merge the prototypes.**\n\n```coffeescript\nclass MyModel extends Mixen(Throttle, APIBinding, Validate, Backbone.Model)\n  # Inheritance Chain:\n  #\n  # MyModel -\u003e Throttle -\u003e APIBinding -\u003e Validate -\u003e Backbone.Model\n\nclass MyOtherModel extends Mixen(APIBinding, Backbone.Model)\n  # Inheritance Chain:\n  #\n  # MyOtherModel -\u003e APIBinding -\u003e Backbone.Model\n```\n\nThe 2kb library only exposes a single function, `Mixen`.  This function allows you to combine\nclasses together in such a way that the `super` keyword will dynamically call the appropriate method in the\nnext mixin you're using.\n\n\u003e Note:\n\u003e\n\u003e These examples are in CoffeeScript.  Skip down to the bottom for a short description of how\n\u003e this can be done with JavaScript.\n\n### Usage\n\nFeel free to [start playing with Mixen](http://jsfiddle.net/4XgaR/7/) right now.\n\nOn the browser include [mixen.min.js](https://raw.github.com/HubSpot/mixen/v0.5.2/mixen.min.js), and the `Mixen` function will be globally available.\nYou can also use AMD.\n\nOn node:\n\n```bash\nnpm install mixen\n```\n\n```coffeescript\nMixen = require('mixen')\n```\n\nThe Mixen function takes in any number of classes, and returns an object:\n\n```coffeescript\nMyObject = Mixen(Object1, Object2, ...)\n```\n\nSkip down for a list of the publicly available mixins.\n\n### Example\n\nA mixin is just a class:\n\n```coffeescript\nclass OnlyRenderWithModel\n  render: -\u003e\n    return unless @model\n\n    super\n```\n\nAny view who would like your method can now use Mixen to mix you in:\n\n```coffeescript\nclass MyView extends Mixen(OnlyRenderWithModel, Backbone.View)\n```\n\nYou can now replace your BaseModels and BaseViews with modular components.\n\n### Multiple Mixins Which Share Methods\n\nMixen adds one very important capability to inheritance, the ability to have multiple mixins all implement the same method.\n\n```coffeescript\nclass CountSyncs\n  sync: -\u003e\n    @syncs = (@syncs or 0) + 1\n\n    super\n```\n\n```coffeescript\nclass ThrottleSyncs\n  sync: -\u003e\n    return if @syncing\n    @syncing = true\n\n    super.finally =\u003e\n      @syncing = false\n```\n\nNow, you can mix in both classes.  When the first mixin calls `super`, it will dynamically find and call the second\nmixin's `sync` method.\n\n```coffeescript\nclass MyModel extends Mixen(ThrottleSyncs, CountSyncs, Backbone.Model)\n```\n\n`MyModel` will both throttle it's sync's and keep track of it's sync count.\n\nNote that the count `CountSyncs` will change depending on if it is listed before or after\n`ThrottleSyncs`.  All methods are resolved from left to right.  In other words,\nwhen you call `super`, you are calling the mixin to the current mixins right.\n\n#### The End of the Chain\n\nWhen you're developing a mixin, you don't know if your mixin will be the last in a chain used\nto create a class or not.  Therefore you must always call super (unless you want to break the chain), and\nyou must always be ready for `super` to return undefined (as it will if there are no more classes mixed in\nwhich implement that method).\n\n```coffeescript\nclass UserInContext\n  getContext: -\u003e\n    context = super ? {}\n    context.user = 'bob smith'\n    context\n\nclass AuthInContext\n  getContext: -\u003e\n    context = super ? {}\n    context.auth = 'logged-in'\n    context\n```\n\nEach getContext method will be called, in the order they are defined in the Mixen call:\n\n```coffeescript\nclass MyView extends Mixen(AuthInContext, UserInContext, Backbone.View)\n  getContext: -\u003e\n    context = super\n    context.x = 2\n    context\n```\n\n### Mixening in Constructors\n\nMixins can have constructors.  As long as the resultant class either does not have a constructor,\nor calls `super` in it's constructor, all of the mixins constructors will be called in the order\nthey are defined.  If you do not wish for the constructors to be called, simply don't call super\nin the constructor of the class extending the mixen.\n\n```coffeescript\nclass CallInitialize\n  constructor: -\u003e\n    @initialize?()\n```\n\n```coffeescript\n# initialize will be called\nclass MyThing extends Mixen(CallInitialize)\n\n# initialize will be called\nclass MyThing extends Mixen(CallInitialize)\n  constructor: -\u003e\n    # Do whatever other stuff you want...\n\n    super\n\n# initialize WON'T be called\nclass MyThing extends Mixen(CallInitialize)\n  constructor: -\u003e\n    # Never called super...\n```\n\nNote, that unlike the other methods, mixins should not call `super` in their constructors.  This is\nnecessary because, unlike with standard methods, all classes have a constructor, even if you never\nexplicitly implemented one.  This means that if we made you call `super`, you would have to explicitly\ncall `super` in each constructor, even when you don't care to specify one.  To keep things simple, we\nalways call all the mixin's constructors in the order they are specified, provided the mixing class doesn't\nexplicitly prevent it.\n\n### Aliases\n\nMixen doesn't create them for you, but you're more than welcome to create some helpful aliases as you need:\n\n```coffeescript\nMixen.View = (modules...) -\u003e\n  Mixen(modules..., Backbone.View)\n```\n\nYou can do a similar thing to create a default list of mixins for your application:\n\n```coffeescript\nViewMixen = (modules...) -\u003e\n  Mixen(modules..., EventJanitor, Backbone.View)\n```\n\n### Composition\n\nYou can safely mixin other mixens:\n\n```coffeescript\nBaseView = Mixen(EventJanitor, Backbone.View)\n\nclass MyView extends Mixen(SuperSpecialModule, BaseView)\n```\n\nDiamond inheritance is not supported yet.\n\n### Not Using CoffeeScript?\n\nIf you're not using CoffeeScript, it is possible to write the necessary js manually.  Replicating CoffeeScript's\ninheritance mechanism is fairly complicated however.  It requires a robust extension mechanism, and replacing every\n`super` call used above with `ModuleName.__super__.methodName`.\n\n```javascript\nvar AuthInContext, MyView, UserInContext;\n\nUserInContext = function (){}\n\nUserInContext.prototype.getContext = function(){\n  var context = UserInContext.__super__.getContext.apply(this, arguments) || {};\n  context.user = 'bob smith';\n  return context;\n};\n\nAuthInContext = function (){}\n\nAuthInContext.prototype.getContext = function(){\n  var context = AuthInContext.__super__.getContext.apply(this, arguments) || {};\n  context.auth = 'logged-in';\n  return context;\n};\n\nMyView = function (){\n  return MyView.__super__.constructor.apply(this, arguments);\n}\n\n__extends(MyView, Mixen(AuthInContext, UserInContext, Backbone.View));\n\nMyView.prototype.getContext = function(){\n  var context = MyView.__super__.getContext.apply(this, arguments);\n  context.x = 2;\n  return context;\n};\n```\n\nWhere `__extends` is implemented as:\n\n```javascript\nvar __hasProp = {}.hasOwnProperty,\n__extends = function(child, parent){\n  for (var key in parent) {\n    if (__hasProp.call(parent, key))\n      child[key] = parent[key];\n  }\n\n  function ctor() {\n    this.constructor = child;\n  }\n\n  ctor.prototype = parent.prototype;\n  child.prototype = new ctor();\n  child.__super__ = parent.prototype;\n\n  return child;\n};\n```\n\n### Debugging\n\nIf it's not working the way you expect, it's usually because you forgot to call `super` in one of your methods.\n\nTake a look at the tests for complete examples of how things should work.\n\nYou can always ask us for help in GitHub Issues.\n\n### Support\n\nMixen is tested in IE6+, Firefox 3+, Chrome 14+, Safari 4+, Opera 10+, Safari on iOS 3+, Android 2.2+ and Node 0.8+.\n\n### Contributing\n\nWe welcome pull requests and discussion using GitHub Issues.\n\nTo get setup for development, run this in the project directory:\n\n```bash\nnpm install\n```\n\nThen, you can run `grunt watch` to have it watch the source files for changes.\nRun `grunt test` to ensure that the tests still pass.\nYou can also open `spec/vendor/jasmine-1.3.1/SpecRunner.html` in your browser to check the tests (after doing a `grunt` build).\n\nIf you create a mixin which others might find useful, please name it `mixen-\u003ctype\u003e-\u003cname\u003e`, where type identifies what sort\nof thing this mixin is designed to extend (leave type out of it's general-purpose).\n\nExamples of good names:\n\nmixen-view-eventjanitor\nmixen-model-throttle\n\n### Mixins\n\n#### Backbone\n\n##### View\n\n- [Event Janitor](http://github.com/HubSpot/mixen-view-eventjanitor)\n\n##### Model\n\n- [Throttle](http://github.com/HubSpot/mixen-model-throttle)\n\nPlease let us know of any interesting Mixen's you make!\n\n### Changelog\n\n- 0.5.0 - Initial public release\n- 0.5.1 - Fix bug with interoperability with Backbone.extend\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubspot%2Fmixen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhubspot%2Fmixen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubspot%2Fmixen/lists"}